mirror of
https://github.com/invoiceninja/invoiceninja.git
synced 2025-05-24 02:14:21 -04:00
Fixes for KRW currency formatting
This commit is contained in:
parent
1459fb2790
commit
f16e8fdd15
@ -244,19 +244,23 @@ class ImportController extends Controller
|
||||
*/
|
||||
public function detectDelimiter($csvfile): string
|
||||
{
|
||||
$delimiters = [',', '.', ';'];
|
||||
$bestDelimiter = ' ';
|
||||
|
||||
$delimiters = [',', '.', ';', '|'];
|
||||
$bestDelimiter = ',';
|
||||
$count = 0;
|
||||
|
||||
// 10-01-2024 - A better way to resolve the csv file delimiter.
|
||||
$csvfile = substr($csvfile, 0, strpos($csvfile, "\n"));
|
||||
|
||||
foreach ($delimiters as $delimiter) {
|
||||
|
||||
if (substr_count(strstr($csvfile, "\n", true), $delimiter) >= $count) {
|
||||
$count = substr_count(strstr($csvfile, "\n", true), $delimiter);
|
||||
$count = substr_count($csvfile, $delimiter);
|
||||
$bestDelimiter = $delimiter;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return $bestDelimiter;
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -63,7 +63,6 @@ class TaskTransformer extends BaseTransformer
|
||||
|
||||
$time_log = collect($task_items_data)
|
||||
->map(function ($item) {
|
||||
|
||||
return $this->parseLog($item);
|
||||
|
||||
})->toJson();
|
||||
@ -80,10 +79,10 @@ class TaskTransformer extends BaseTransformer
|
||||
|
||||
$notes = $item['task.notes'] ?? '';
|
||||
|
||||
if(isset($item['task.is_billable']) && is_string($item['task.is_billable']) && in_array($item['task.is_billable'], ['yes', 'true', '1'])) {
|
||||
if(isset($item['task.billable']) && is_string($item['task.billable']) && in_array($item['task.billable'], ['yes', 'true', '1', 'TRUE', 'YES'])) {
|
||||
$is_billable = true;
|
||||
} elseif(isset($item['task.is_billable']) && is_bool($item['task.is_billable'])) {
|
||||
$is_billable = $item['task.is_billable'];
|
||||
} elseif(isset($item['task.billable']) && is_bool($item['task.billable'])) {
|
||||
$is_billable = $item['task.billable'];
|
||||
} else {
|
||||
$is_billable = false;
|
||||
}
|
||||
|
@ -34,6 +34,7 @@ use Illuminate\Queue\SerializesModels;
|
||||
use Illuminate\Support\Facades\App;
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use Hyvor\JsonExporter\File;
|
||||
|
||||
class CompanyExport implements ShouldQueue
|
||||
{
|
||||
@ -46,8 +47,8 @@ class CompanyExport implements ShouldQueue
|
||||
private $export_format = 'json';
|
||||
|
||||
private $export_data = [];
|
||||
|
||||
|
||||
private $writer;
|
||||
private $file_name;
|
||||
/**
|
||||
* Create a new job instance.
|
||||
*
|
||||
@ -67,13 +68,23 @@ class CompanyExport implements ShouldQueue
|
||||
public function handle()
|
||||
{
|
||||
MultiDB::setDb($this->company->db);
|
||||
nlog("starting export");
|
||||
|
||||
|
||||
|
||||
$this->file_name = date('Y-m-d') . '_' . str_replace([" ", "/"], ["_",""], $this->company->present()->name() . '_' . $this->company->company_key . '.json');
|
||||
|
||||
$this->writer = new File($this->file_name);
|
||||
|
||||
$info = $this->writer->collection('');
|
||||
|
||||
|
||||
|
||||
set_time_limit(0);
|
||||
|
||||
$this->export_data['app_version'] = config('ninja.app_version');
|
||||
$this->export_data['storage_url'] = Storage::url('');
|
||||
|
||||
|
||||
$info->addItems($this->export_data);
|
||||
|
||||
$this->export_data['activities'] = $this->company->all_activities->map(function ($activity) {
|
||||
$activity = $this->transformArrayOfKeys($activity, [
|
||||
'user_id',
|
||||
@ -98,27 +109,21 @@ class CompanyExport implements ShouldQueue
|
||||
return $activity;
|
||||
})->makeHidden(['id'])->all();
|
||||
|
||||
// $this->export_data['backups'] = $this->company->all_activities()->with('backup')->cursor()->map(function ($activity){
|
||||
|
||||
// $backup = $activity->backup;
|
||||
$x = $this->writer->collection('activities');
|
||||
$x->addItems($this->export_data['activities']);
|
||||
$this->export_data = null;
|
||||
|
||||
// if(!$backup)
|
||||
// return;
|
||||
|
||||
// $backup->activity_id = $this->encodePrimaryKey($backup->activity_id);
|
||||
|
||||
// return $backup;
|
||||
|
||||
// })->all();
|
||||
|
||||
$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();
|
||||
|
||||
|
||||
$x = $this->writer->collection('users');
|
||||
$x->addItems($this->export_data['users']);
|
||||
$this->export_data = null;
|
||||
|
||||
$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']);
|
||||
|
||||
@ -138,6 +143,10 @@ class CompanyExport implements ShouldQueue
|
||||
})->all();
|
||||
|
||||
|
||||
$x = $this->writer->collection('client_contacts');
|
||||
$x->addItems($this->export_data['client_contacts']);
|
||||
$this->export_data = null;
|
||||
|
||||
$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']);
|
||||
|
||||
@ -145,6 +154,10 @@ class CompanyExport implements ShouldQueue
|
||||
})->all();
|
||||
|
||||
|
||||
$x = $this->writer->collection('client_gateway_tokens');
|
||||
$x->addItems($this->export_data['client_gateway_tokens']);
|
||||
$this->export_data = null;
|
||||
|
||||
$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']);
|
||||
$client->tax_data = '';
|
||||
@ -152,9 +165,20 @@ class CompanyExport implements ShouldQueue
|
||||
})->all();
|
||||
|
||||
|
||||
$x = $this->writer->collection('clients');
|
||||
$x->addItems($this->export_data['clients']);
|
||||
$this->export_data = null;
|
||||
|
||||
$this->export_data['company'] = $this->company->toArray();
|
||||
$this->export_data['company']['company_key'] = $this->createHash();
|
||||
|
||||
|
||||
|
||||
$x = $this->writer->collection('company');
|
||||
$x->addItems($this->export_data['company']);
|
||||
$this->export_data = null;
|
||||
|
||||
|
||||
$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);
|
||||
@ -162,25 +186,49 @@ class CompanyExport implements ShouldQueue
|
||||
return $company_gateway->makeVisible(['id']);
|
||||
})->all();
|
||||
|
||||
|
||||
$x = $this->writer->collection('company_gateways');
|
||||
$x->addItems($this->export_data['company_gateways']);
|
||||
$this->export_data = null;
|
||||
|
||||
|
||||
|
||||
|
||||
$this->export_data['company_tokens'] = $this->company->tokens->map(function ($token) {
|
||||
$token = $this->transformArrayOfKeys($token, ['company_id', 'account_id', 'user_id']);
|
||||
|
||||
return $token;
|
||||
})->all();
|
||||
|
||||
|
||||
$x = $this->writer->collection('company_tokens');
|
||||
$x->addItems($this->export_data['company_tokens']);
|
||||
$this->export_data = null;
|
||||
|
||||
|
||||
$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();
|
||||
|
||||
|
||||
$x = $this->writer->collection('company_ledger');
|
||||
$x->addItems($this->export_data['company_ledger']);
|
||||
$this->export_data = null;
|
||||
|
||||
|
||||
$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->makeHidden(['react_settings']);
|
||||
return $company_user;
|
||||
})->all();
|
||||
|
||||
|
||||
$x = $this->writer->collection('company_users');
|
||||
$x->addItems($this->export_data['company_users']);
|
||||
$this->export_data = null;
|
||||
|
||||
|
||||
$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']);
|
||||
@ -188,6 +236,10 @@ class CompanyExport implements ShouldQueue
|
||||
return $credit->makeVisible(['id']);
|
||||
})->all();
|
||||
|
||||
$x = $this->writer->collection('credits');
|
||||
$x->addItems($this->export_data['credits']);
|
||||
$this->export_data = null;
|
||||
|
||||
|
||||
$this->export_data['credit_invitations'] = CreditInvitation::query()->where('company_id', $this->company->id)->withTrashed()->cursor()->map(function ($credit) {
|
||||
$credit = $this->transformArrayOfKeys($credit, ['company_id', 'user_id', 'client_contact_id', 'credit_id']);
|
||||
@ -195,8 +247,20 @@ class CompanyExport implements ShouldQueue
|
||||
return $credit->makeVisible(['id']);
|
||||
})->all();
|
||||
|
||||
|
||||
$x = $this->writer->collection('credit_invitations');
|
||||
$x->addItems($this->export_data['credit_invitations']);
|
||||
$this->export_data = null;
|
||||
|
||||
|
||||
$this->export_data['designs'] = $this->company->user_designs->makeHidden(['id'])->all();
|
||||
|
||||
|
||||
$x = $this->writer->collection('designs');
|
||||
$x->addItems($this->export_data['designs']);
|
||||
$this->export_data = null;
|
||||
|
||||
|
||||
$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);
|
||||
@ -204,12 +268,20 @@ class CompanyExport implements ShouldQueue
|
||||
return $document->makeVisible(['id']);
|
||||
})->all();
|
||||
|
||||
$x = $this->writer->collection('documents');
|
||||
$x->addItems($this->export_data['documents']);
|
||||
$this->export_data = null;
|
||||
|
||||
$this->export_data['expense_categories'] = $this->company->expense_categories()->cursor()->map(function ($expense_category) {
|
||||
$expense_category = $this->transformArrayOfKeys($expense_category, ['user_id', 'company_id']);
|
||||
|
||||
return $expense_category->makeVisible(['id']);
|
||||
})->all();
|
||||
|
||||
$x = $this->writer->collection('expense_categories');
|
||||
$x->addItems($this->export_data['expense_categories']);
|
||||
$this->export_data = null;
|
||||
|
||||
|
||||
$this->export_data['expenses'] = $this->company->expenses()->orderBy('number', 'DESC')->cursor()->map(function ($expense) {
|
||||
$expense = $this->transformBasicEntities($expense);
|
||||
@ -218,12 +290,23 @@ class CompanyExport implements ShouldQueue
|
||||
return $expense->makeVisible(['id']);
|
||||
})->all();
|
||||
|
||||
|
||||
$x = $this->writer->collection('expenses');
|
||||
$x->addItems($this->export_data['expenses']);
|
||||
$this->export_data = null;
|
||||
|
||||
|
||||
$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();
|
||||
|
||||
|
||||
$x = $this->writer->collection('group_settings');
|
||||
$x->addItems($this->export_data['group_settings']);
|
||||
$this->export_data = null;
|
||||
|
||||
|
||||
$this->export_data['invoices'] = $this->company->invoices()->orderBy('number', 'DESC')->cursor()->map(function ($invoice) {
|
||||
$invoice = $this->transformBasicEntities($invoice);
|
||||
@ -238,18 +321,33 @@ class CompanyExport implements ShouldQueue
|
||||
})->all();
|
||||
|
||||
|
||||
$x = $this->writer->collection('invoices');
|
||||
$x->addItems($this->export_data['invoices']);
|
||||
$this->export_data = null;
|
||||
|
||||
$this->export_data['invoice_invitations'] = InvoiceInvitation::query()->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();
|
||||
|
||||
|
||||
$x = $this->writer->collection('invoice_invitations');
|
||||
$x->addItems($this->export_data['invoice_invitations']);
|
||||
$this->export_data = null;
|
||||
|
||||
|
||||
$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();
|
||||
|
||||
|
||||
$x = $this->writer->collection('payment_terms');
|
||||
$x->addItems($this->export_data['payment_terms']);
|
||||
$this->export_data = null;
|
||||
|
||||
|
||||
$this->export_data['payments'] = $this->company->payments()->orderBy('number', 'DESC')->cursor()->map(function ($payment) {
|
||||
$payment = $this->transformBasicEntities($payment);
|
||||
@ -260,6 +358,13 @@ class CompanyExport implements ShouldQueue
|
||||
return $payment->makeVisible(['id']);
|
||||
})->all();
|
||||
|
||||
|
||||
|
||||
$x = $this->writer->collection('payments');
|
||||
$x->addItems($this->export_data['payments']);
|
||||
$this->export_data = null;
|
||||
|
||||
|
||||
$this->export_data['products'] = $this->company->products->map(function ($product) {
|
||||
$product = $this->transformBasicEntities($product);
|
||||
$product = $this->transformArrayOfKeys($product, ['vendor_id','project_id']);
|
||||
@ -267,6 +372,12 @@ class CompanyExport implements ShouldQueue
|
||||
return $product->makeVisible(['id']);
|
||||
})->all();
|
||||
|
||||
|
||||
$x = $this->writer->collection('products');
|
||||
$x->addItems($this->export_data['products']);
|
||||
$this->export_data = null;
|
||||
|
||||
|
||||
$this->export_data['projects'] = $this->company->projects()->orderBy('number', 'DESC')->cursor()->map(function ($project) {
|
||||
$project = $this->transformBasicEntities($project);
|
||||
$project = $this->transformArrayOfKeys($project, ['client_id']);
|
||||
@ -274,6 +385,12 @@ class CompanyExport implements ShouldQueue
|
||||
return $project->makeVisible(['id']);
|
||||
})->all();
|
||||
|
||||
|
||||
$x = $this->writer->collection('projects');
|
||||
$x->addItems($this->export_data['projects']);
|
||||
$this->export_data = null;
|
||||
|
||||
|
||||
$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']);
|
||||
@ -281,6 +398,11 @@ class CompanyExport implements ShouldQueue
|
||||
return $quote->makeVisible(['id']);
|
||||
})->all();
|
||||
|
||||
|
||||
$x = $this->writer->collection('quotes');
|
||||
$x->addItems($this->export_data['quotes']);
|
||||
$this->export_data = null;
|
||||
|
||||
|
||||
$this->export_data['quote_invitations'] = QuoteInvitation::query()->where('company_id', $this->company->id)->withTrashed()->cursor()->map(function ($quote) {
|
||||
$quote = $this->transformArrayOfKeys($quote, ['company_id', 'user_id', 'client_contact_id', 'quote_id']);
|
||||
@ -288,6 +410,12 @@ class CompanyExport implements ShouldQueue
|
||||
return $quote->makeVisible(['id']);
|
||||
})->all();
|
||||
|
||||
|
||||
$x = $this->writer->collection('quote_invitations');
|
||||
$x->addItems($this->export_data['quote_invitations']);
|
||||
$this->export_data = null;
|
||||
|
||||
|
||||
$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']);
|
||||
@ -295,6 +423,13 @@ class CompanyExport implements ShouldQueue
|
||||
return $expense->makeVisible(['id']);
|
||||
})->all();
|
||||
|
||||
|
||||
|
||||
$x = $this->writer->collection('recurring_expenses');
|
||||
$x->addItems($this->export_data['recurring_expenses']);
|
||||
$this->export_data = null;
|
||||
|
||||
|
||||
$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']);
|
||||
@ -302,6 +437,11 @@ class CompanyExport implements ShouldQueue
|
||||
return $ri->makeVisible(['id']);
|
||||
})->all();
|
||||
|
||||
|
||||
$x = $this->writer->collection('recurring_invoices');
|
||||
$x->addItems($this->export_data['recurring_invoices']);
|
||||
$this->export_data = null;
|
||||
|
||||
|
||||
$this->export_data['recurring_invoice_invitations'] = RecurringInvoiceInvitation::query()->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']);
|
||||
@ -309,6 +449,13 @@ class CompanyExport implements ShouldQueue
|
||||
return $ri;
|
||||
})->all();
|
||||
|
||||
|
||||
$x = $this->writer->collection('recurring_invoice_invitations');
|
||||
$x->addItems($this->export_data['recurring_invoice_invitations']);
|
||||
$this->export_data = null;
|
||||
|
||||
|
||||
|
||||
$this->export_data['subscriptions'] = $this->company->subscriptions->map(function ($subscription) {
|
||||
$subscription = $this->transformBasicEntities($subscription);
|
||||
$subscription->group_id = $this->encodePrimaryKey($subscription->group_id);
|
||||
@ -323,6 +470,10 @@ class CompanyExport implements ShouldQueue
|
||||
})->all();
|
||||
|
||||
|
||||
$x = $this->writer->collection('subscriptions');
|
||||
$x->addItems($this->export_data['subscriptions']);
|
||||
$this->export_data = null;
|
||||
|
||||
$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);
|
||||
@ -330,14 +481,26 @@ class CompanyExport implements ShouldQueue
|
||||
return $log;
|
||||
})->makeHidden(['id'])->all();
|
||||
|
||||
|
||||
$x = $this->writer->collection('system_logs');
|
||||
$x->addItems($this->export_data['system_logs']);
|
||||
$this->export_data = null;
|
||||
|
||||
|
||||
$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->makeHidden(['hash','meta'])->makeVisible(['id']);
|
||||
// return $task->makeHidden(['hash','meta'])->makeVisible(['id']); //@release v5.7.63
|
||||
})->all();
|
||||
|
||||
|
||||
|
||||
$x = $this->writer->collection('tasks');
|
||||
$x->addItems($this->export_data['tasks']);
|
||||
$this->export_data = null;
|
||||
|
||||
|
||||
$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);
|
||||
@ -346,6 +509,13 @@ class CompanyExport implements ShouldQueue
|
||||
return $status;
|
||||
})->all();
|
||||
|
||||
|
||||
|
||||
$x = $this->writer->collection('task_statuses');
|
||||
$x->addItems($this->export_data['task_statuses']);
|
||||
$this->export_data = null;
|
||||
|
||||
|
||||
$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);
|
||||
@ -353,11 +523,24 @@ class CompanyExport implements ShouldQueue
|
||||
return $rate;
|
||||
})->makeHidden(['id'])->all();
|
||||
|
||||
|
||||
|
||||
$x = $this->writer->collection('tax_rates');
|
||||
$x->addItems($this->export_data['tax_rates']);
|
||||
$this->export_data = null;
|
||||
|
||||
|
||||
$this->export_data['vendors'] = $this->company->vendors()->orderBy('number', 'DESC')->cursor()->map(function ($vendor) {
|
||||
return $this->transformBasicEntities($vendor)->makeVisible(['id']);
|
||||
})->all();
|
||||
|
||||
|
||||
|
||||
$x = $this->writer->collection('vendors');
|
||||
$x->addItems($this->export_data['vendors']);
|
||||
$this->export_data = null;
|
||||
|
||||
|
||||
$this->export_data['vendor_contacts'] = VendorContact::where('company_id', $this->company->id)->withTrashed()->cursor()->map(function ($vendor) {
|
||||
$vendor = $this->transformBasicEntities($vendor);
|
||||
$vendor = $this->transformArrayOfKeys($vendor, ['vendor_id']);
|
||||
@ -365,6 +548,13 @@ class CompanyExport implements ShouldQueue
|
||||
return $vendor->makeVisible(['id','user_id']);
|
||||
})->all();
|
||||
|
||||
|
||||
|
||||
$x = $this->writer->collection('vendor_contacts');
|
||||
$x->addItems($this->export_data['vendor_contacts']);
|
||||
$this->export_data = null;
|
||||
|
||||
|
||||
$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);
|
||||
@ -372,6 +562,12 @@ class CompanyExport implements ShouldQueue
|
||||
return $hook;
|
||||
})->makeHidden(['id'])->all();
|
||||
|
||||
|
||||
$x = $this->writer->collection('webhooks');
|
||||
$x->addItems($this->export_data['webhooks']);
|
||||
$this->export_data = null;
|
||||
|
||||
|
||||
$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']);
|
||||
@ -384,6 +580,13 @@ class CompanyExport implements ShouldQueue
|
||||
'company_id',]);
|
||||
})->all();
|
||||
|
||||
|
||||
$x = $this->writer->collection('purchase_orders');
|
||||
$x->addItems($this->export_data['purchase_orders']);
|
||||
$this->export_data = null;
|
||||
|
||||
|
||||
|
||||
$this->export_data['purchase_order_invitations'] = PurchaseOrderInvitation::query()->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']);
|
||||
|
||||
@ -391,26 +594,46 @@ class CompanyExport implements ShouldQueue
|
||||
})->all();
|
||||
|
||||
|
||||
$x = $this->writer->collection('purchase_order_invitations');
|
||||
$x->addItems($this->export_data['purchase_order_invitations']);
|
||||
$this->export_data = null;
|
||||
|
||||
$this->export_data['bank_integrations'] = $this->company->bank_integrations()->withTrashed()->orderBy('id', 'ASC')->cursor()->map(function ($bank_integration) {
|
||||
$bank_integration = $this->transformArrayOfKeys($bank_integration, ['account_id','company_id', 'user_id']);
|
||||
|
||||
return $bank_integration->makeVisible(['id','user_id','company_id','account_id','hashed_id']);
|
||||
})->all();
|
||||
|
||||
$x = $this->writer->collection('bank_integrations');
|
||||
$x->addItems($this->export_data['bank_integrations']);
|
||||
$this->export_data = null;
|
||||
|
||||
$this->export_data['bank_transactions'] = $this->company->bank_transactions()->withTrashed()->orderBy('id', 'ASC')->cursor()->map(function ($bank_transaction) {
|
||||
$bank_transaction = $this->transformArrayOfKeys($bank_transaction, ['company_id', 'user_id','bank_integration_id','expense_id','ninja_category_id','vendor_id']);
|
||||
|
||||
return $bank_transaction->makeVisible(['id','user_id','company_id']);
|
||||
})->all();
|
||||
|
||||
$x = $this->writer->collection('bank_transactions');
|
||||
$x->addItems($this->export_data['bank_transactions']);
|
||||
$this->export_data = null;
|
||||
|
||||
$this->export_data['schedulers'] = $this->company->schedulers()->withTrashed()->orderBy('id', 'ASC')->cursor()->map(function ($scheduler) {
|
||||
$scheduler = $this->transformArrayOfKeys($scheduler, ['company_id', 'user_id']);
|
||||
|
||||
return $scheduler->makeVisible(['id','user_id','company_id']);
|
||||
})->all();
|
||||
|
||||
$x = $this->writer->collection('schedulers');
|
||||
$x->addItems($this->export_data['schedulers']);
|
||||
$this->export_data = null;
|
||||
|
||||
//write to tmp and email to owner();
|
||||
|
||||
|
||||
$this->writer->end();
|
||||
|
||||
|
||||
$this->zipAndSend();
|
||||
|
||||
return true;
|
||||
@ -446,38 +669,40 @@ class CompanyExport implements ShouldQueue
|
||||
|
||||
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';
|
||||
$zip_path = \Illuminate\Support\Str::ascii(str_replace(".json", ".zip", $this->file_name));
|
||||
// $path = 'backups';
|
||||
|
||||
// Storage::makeDirectory(storage_path('backups/'));
|
||||
|
||||
try {
|
||||
mkdir(storage_path('backups/'));
|
||||
} catch(\Exception $e) {
|
||||
nlog("could not create directory");
|
||||
}
|
||||
// try {
|
||||
// mkdir(storage_path('backups/'));
|
||||
// } catch(\Exception $e) {
|
||||
// nlog("could not create directory");
|
||||
// }
|
||||
|
||||
$zip_path = storage_path('backups/'.\Illuminate\Support\Str::ascii($file_name));
|
||||
// $zip_path = storage_path('backups/'.\Illuminate\Support\Str::ascii($file_name));
|
||||
$zip = new \ZipArchive();
|
||||
|
||||
if ($zip->open($zip_path, \ZipArchive::CREATE) !== true) {
|
||||
nlog("cannot open {$zip_path}");
|
||||
}
|
||||
|
||||
$zip->addFromString("backup.json", json_encode($this->export_data));
|
||||
$zip->addFile($this->file_name, 'backup.json');
|
||||
// $zip->addFromString("backup.json", json_encode($this->export_data));
|
||||
$zip->close();
|
||||
|
||||
Storage::disk(config('filesystems.default'))->put('backups/'.$file_name, file_get_contents($zip_path));
|
||||
Storage::disk(config('filesystems.default'))->put('backups/'.str_replace(".json", ".zip",$this->file_name), file_get_contents($zip_path));
|
||||
|
||||
if(file_exists($zip_path)) {
|
||||
unlink($zip_path);
|
||||
}
|
||||
|
||||
if(Ninja::isSelfHost()) {
|
||||
$storage_path = 'backups/'.$file_name;
|
||||
$storage_path = 'backups/'.str_replace(".json", ".zip",$this->file_name);
|
||||
} else {
|
||||
$storage_path = Storage::disk(config('filesystems.default'))->path('backups/'.$file_name);
|
||||
$storage_path = Storage::disk(config('filesystems.default'))->path('backups/'.str_replace(".json", ".zip",$this->file_name));
|
||||
}
|
||||
|
||||
$url = Cache::get($this->hash);
|
||||
|
@ -278,7 +278,6 @@ class CompanyImport implements ShouldQueue
|
||||
throw new \Exception('No import data found, has the cache expired?');
|
||||
}
|
||||
|
||||
// $this->backup_file = json_decode(file_get_contents($this->file_location));
|
||||
$tmp_file = $this->unzipFile();
|
||||
|
||||
$this->file_path = $tmp_file;
|
||||
@ -341,15 +340,37 @@ class CompanyImport implements ShouldQueue
|
||||
{
|
||||
$path = TempFile::filePath(Storage::disk(config('filesystems.default'))->get($this->file_location), basename($this->file_location));
|
||||
|
||||
nlog($path);
|
||||
$zip = new ZipArchive();
|
||||
$archive = $zip->open($path);
|
||||
$res = $zip->open($path, ZipArchive::OVERWRITE);
|
||||
|
||||
$file_path = sys_get_temp_dir().'/'.sha1(microtime());
|
||||
|
||||
$zip->extractTo($file_path);
|
||||
$zip->close();
|
||||
$file_location = "{$file_path}/backup.json";
|
||||
|
||||
if ($res === true) {
|
||||
echo 'ok';
|
||||
$zip->extractTo('test');
|
||||
$zip->close();
|
||||
|
||||
|
||||
// $file_path = sys_get_temp_dir().'/'.sha1(microtime());
|
||||
|
||||
// nlog($file_path);
|
||||
|
||||
// $result = $zip->extractTo($file_path);
|
||||
|
||||
$result = $zip->extractTo(".");
|
||||
|
||||
nlog($result);
|
||||
|
||||
$$zip->close();
|
||||
|
||||
} else {
|
||||
echo 'failed, code:' . $res;
|
||||
}
|
||||
|
||||
|
||||
$file_location = "backup.json";
|
||||
$file_path = $file_location;
|
||||
if (! file_exists($file_path)) {
|
||||
throw new NonExistingMigrationFile('Backup file does not exist, or is corrupted.');
|
||||
}
|
||||
|
@ -260,11 +260,36 @@ class NinjaMailerJob implements ShouldQueue
|
||||
$t->replace(Ninja::transformTranslations($this->nmo->settings));
|
||||
|
||||
/** Force free/trials onto specific mail driver */
|
||||
if(Ninja::isHosted() && !$this->company->account->isPaid())
|
||||
{
|
||||
$this->mailer = 'mailgun';
|
||||
$this->setHostedMailgunMailer();
|
||||
return $this;
|
||||
// if(Ninja::isHosted() && !$this->company->account->isPaid())
|
||||
// {
|
||||
// $this->mailer = 'mailgun';
|
||||
// $this->setHostedMailgunMailer();
|
||||
// return $this;
|
||||
// }
|
||||
|
||||
if(Ninja::isHosted() && $this->company->account->isPaid() && $this->nmo->settings->email_sending_method == 'default') {
|
||||
//check if outlook.
|
||||
|
||||
try{
|
||||
$email = $this->nmo->to_user->email;
|
||||
$domain = explode("@", $email)[1] ?? "";
|
||||
$dns = dns_get_record($domain, DNS_MX);
|
||||
$server = $dns[0]["target"];
|
||||
if(stripos($server, "outlook.com") !== false){
|
||||
|
||||
$this->mailer = 'postmark';
|
||||
$this->client_postmark_secret = config('services.postmark-outlook.token');
|
||||
|
||||
$this->nmo
|
||||
->mailable
|
||||
->from('maildelivery@invoice.services', 'Invoice Ninja');
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
catch(\Exception $e){
|
||||
nlog($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
switch ($this->nmo->settings->email_sending_method) {
|
||||
|
@ -45,6 +45,7 @@ class QuoteCreatedNotification implements ShouldQueue
|
||||
|
||||
|
||||
/* We loop through each user and determine whether they need to be notified */
|
||||
/** @var \App\Models\CompanyUser $company_user */
|
||||
foreach ($event->company->company_users as $company_user) {
|
||||
/* The User */
|
||||
$user = $company_user->user;
|
||||
|
@ -201,7 +201,7 @@ class CompanyUser extends Pivot
|
||||
* @return bool
|
||||
*/
|
||||
public function portalType(): bool
|
||||
{
|
||||
{ nlog(isset($this->react_settings->react_notification_link) && $this->react_settings->react_notification_link);
|
||||
return isset($this->react_settings->react_notification_link) && $this->react_settings->react_notification_link;
|
||||
}
|
||||
|
||||
|
@ -204,7 +204,7 @@ class Credit extends BaseModel
|
||||
|
||||
public function getDueDateAttribute($value)
|
||||
{
|
||||
return $this->dateMutator($value);
|
||||
return $value ? $this->dateMutator($value) : null;
|
||||
}
|
||||
|
||||
public function getPartialDueDateAttribute($value)
|
||||
|
@ -220,7 +220,7 @@ class Document extends BaseModel
|
||||
$img = new \Imagick();
|
||||
$img->readImageBlob($file);
|
||||
$img->setImageCompression(true);
|
||||
$img->setImageCompressionQuality(50);
|
||||
$img->setImageCompressionQuality(40);
|
||||
|
||||
return $img->getImageBlob();
|
||||
|
||||
|
@ -486,10 +486,34 @@ class Email implements ShouldQueue
|
||||
{
|
||||
|
||||
/** Force free/trials onto specific mail driver */
|
||||
if(Ninja::isHosted() && !$this->company->account->isPaid()) {
|
||||
$this->mailer = 'mailgun';
|
||||
$this->setHostedMailgunMailer();
|
||||
return $this;
|
||||
// if(Ninja::isHosted() && !$this->company->account->isPaid()) {
|
||||
// $this->mailer = 'mailgun';
|
||||
// $this->setHostedMailgunMailer();
|
||||
// return $this;
|
||||
// }
|
||||
|
||||
if(Ninja::isHosted() && $this->company->account->isPaid() && $this->email_object->settings->email_sending_method == 'default') {
|
||||
|
||||
try {
|
||||
|
||||
$address_object = reset($this->email_object->to);
|
||||
$email = $address_object->address ?? '';
|
||||
$domain = explode("@", $email)[1] ?? "";
|
||||
$dns = dns_get_record($domain, DNS_MX);
|
||||
$server = $dns[0]["target"];
|
||||
if(stripos($server, "outlook.com") !== false) {
|
||||
|
||||
|
||||
$this->mailer = 'postmark';
|
||||
$this->client_postmark_secret = config('services.postmark-outlook.token');
|
||||
$this->mailable
|
||||
->from('maildelivery@invoice.services', 'Invoice Ninja');
|
||||
|
||||
return $this;
|
||||
}
|
||||
} catch(\Exception $e) {
|
||||
nlog($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
switch ($this->email_object->settings->email_sending_method) {
|
||||
|
@ -384,7 +384,7 @@ class HtmlEngine
|
||||
|
||||
$data['$total'] = ['value' => Number::formatMoney($this->entity_calc->getTotal(), $this->client) ?: ' ', 'label' => ctrans('texts.total')];
|
||||
$data['$amount'] = &$data['$total'];
|
||||
$data['$amount_due'] = ['value' => &$data['$total']['value'], 'label' => ctrans('texts.amount_due')];
|
||||
$data['$amount_due'] = ['value' => &$data['$balance_due']['value'], 'label' => ctrans('texts.amount_due')];
|
||||
$data['$quote.total'] = &$data['$total'];
|
||||
$data['$invoice.total'] = ['value' => Number::formatMoney($this->entity_calc->getTotal(), $this->client) ?: ' ', 'label' => ctrans('texts.invoice_total')];
|
||||
$data['$invoice_total_raw'] = ['value' => $this->entity_calc->getTotal(), 'label' => ctrans('texts.invoice_total')];
|
||||
|
@ -112,6 +112,7 @@
|
||||
"fakerphp/faker": "^1.14",
|
||||
"filp/whoops": "^2.7",
|
||||
"friendsofphp/php-cs-fixer": "^3.14",
|
||||
"hyvor/php-json-exporter": "^0.0.3",
|
||||
"laracasts/cypress": "^3.0",
|
||||
"larastan/larastan": "^2",
|
||||
"mockery/mockery": "^1.4.4",
|
||||
@ -119,7 +120,6 @@
|
||||
"phpstan/phpstan": "^1.9",
|
||||
"phpunit/phpunit": "^10.0",
|
||||
"spatie/laravel-ignition": "^2.0",
|
||||
"spatie/laravel-open-telemetry": "^0.0.9",
|
||||
"spaze/phpstan-stripe": "^3.0"
|
||||
},
|
||||
"autoload": {
|
||||
|
708
composer.lock
generated
708
composer.lock
generated
File diff suppressed because it is too large
Load Diff
@ -34,6 +34,10 @@ return [
|
||||
'token' => env('POSTMARK_SECRET', ''),
|
||||
],
|
||||
|
||||
'postmark-outlook' => [
|
||||
'token' => env('POSTMARK_OUTLOOK_SECRET','')
|
||||
],
|
||||
|
||||
'microsoft' => [
|
||||
'client_id' => env('MICROSOFT_CLIENT_ID'),
|
||||
'client_secret' => env('MICROSOFT_CLIENT_SECRET'),
|
||||
|
@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
use App\Models\Currency;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
if($c = Currency::find(79)) {
|
||||
$c->thousand_separator = ',';
|
||||
$c->decimal_separator = '.';
|
||||
$c->save();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
//
|
||||
}
|
||||
};
|
@ -101,7 +101,7 @@ class CurrenciesSeeder extends Seeder
|
||||
['id' => 76, 'name' => 'Surinamese Dollar', 'code' => 'SRD', 'symbol' => 'SRD', 'precision' => '2', 'thousand_separator' => '.', 'decimal_separator' => ','],
|
||||
['id' => 77, 'name' => 'Bahraini Dinar', 'code' => 'BHD', 'symbol' => 'BD ', 'precision' => '2', 'thousand_separator' => ',', 'decimal_separator' => '.'],
|
||||
['id' => 78, 'name' => 'Venezuelan Bolivars', 'code' => 'VES', 'symbol' => 'Bs.', 'precision' => '2', 'thousand_separator' => '.', 'decimal_separator' => ','],
|
||||
['id' => 79, 'name' => 'South Korean Won', 'code' => 'KRW', 'symbol' => 'W ', 'precision' => '2', 'thousand_separator' => '.', 'decimal_separator' => ','],
|
||||
['id' => 79, 'name' => 'South Korean Won', 'code' => 'KRW', 'symbol' => 'W ', 'precision' => '2', 'thousand_separator' => ',', 'decimal_separator' => '.'],
|
||||
['id' => 80, 'name' => 'Moroccan Dirham', 'code' => 'MAD', 'symbol' => 'MAD ', 'precision' => '2', 'thousand_separator' => ',', 'decimal_separator' => '.'],
|
||||
['id' => 81, 'name' => 'Jamaican Dollar', 'code' => 'JMD', 'symbol' => '$', 'precision' => '2', 'thousand_separator' => ',', 'decimal_separator' => '.'],
|
||||
['id' => 82, 'name' => 'Angolan Kwanza', 'code' => 'AOA', 'symbol' => 'Kz', 'precision' => '2', 'thousand_separator' => '.', 'decimal_separator' => ','],
|
||||
|
30
phpstan.neon
30
phpstan.neon
@ -1,30 +0,0 @@
|
||||
includes:
|
||||
- ./vendor/larastan/larastan/extension.neon
|
||||
- ./vendor/spaze/phpstan-stripe/extension.neon
|
||||
- phpstan-baseline.neon
|
||||
parameters:
|
||||
level: 2
|
||||
paths:
|
||||
- app
|
||||
excludePaths:
|
||||
- 'vendor/*'
|
||||
- 'resources/*/*.php'
|
||||
- 'app/Jobs/Ninja/*'
|
||||
- 'app/Models/Presenters/*'
|
||||
- 'app/Console/Commands/*'
|
||||
- 'app/DataMapper/Analytics/*'
|
||||
- 'app/PaymentDrivers/Authorize/*'
|
||||
- 'app/PaymentDrivers/AuthorizePaymentDriver.php'
|
||||
- 'app/Utils/Traits/*'
|
||||
universalObjectCratesClasses:
|
||||
- App\DataMapper\Tax\RuleInterface
|
||||
- App\DataMapper\FeesAndLimits
|
||||
- \Postmark\Models\DynamicResponseModel
|
||||
- \Stripe\Collection
|
||||
reportUnmatchedIgnoredErrors: false
|
||||
ignoreErrors:
|
||||
- '#Array has 2 duplicate keys with value#'
|
||||
- '#Call to an undefined method#'
|
||||
- '#makeHidden#'
|
||||
- '#Socialite#'
|
||||
- '#Access to protected property#'
|
31
phpunit.xml
31
phpunit.xml
@ -1,31 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" backupGlobals="false"
|
||||
bootstrap="vendor/autoload.php" colors="true" processIsolation="true" stopOnError="true" stopOnFailure="true" xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/10.3/phpunit.xsd"
|
||||
cacheDirectory=".phpunit.cache" backupStaticProperties="false">
|
||||
<testsuites>
|
||||
<testsuite name="Unit">
|
||||
<directory suffix="Test.php">./tests/Unit</directory>
|
||||
</testsuite>
|
||||
<testsuite name="Integration">
|
||||
<directory suffix="Test.php">./tests/Integration</directory>
|
||||
</testsuite>
|
||||
<testsuite name="Feature">
|
||||
<directory suffix="Test.php">./tests/Feature</directory>
|
||||
</testsuite>
|
||||
<testsuite name="Pdf">
|
||||
<directory suffix="Test.php">./tests/Pdf</directory>
|
||||
</testsuite>
|
||||
</testsuites>
|
||||
<php>
|
||||
<env name="APP_ENV" value="testing"/>
|
||||
<env name="BCRYPT_ROUNDS" value="4"/>
|
||||
<env name="CACHE_DRIVER" value="file"/>
|
||||
<env name="SESSION_DRIVER" value="array"/>
|
||||
<env name="QUEUE_CONNECTION" value="sync"/>
|
||||
<env name="MAIL_MAILER" value="array"/>
|
||||
<env name="DB_CONNECTION" value="sqlite"/>
|
||||
<env name="DB_DATABASE" value=":memory:"/>
|
||||
<env name="DB_STRICT" value="FALSE"/>
|
||||
</php>
|
||||
<logging/>
|
||||
</phpunit>
|
@ -1,4 +1,4 @@
|
||||
@component('email.template.admin', ['design' => 'light', 'settings' => $settings, 'logo' => $logo])
|
||||
@component('email.template.admin', ['design' => 'light', 'settings' => $settings, 'logo' => $logo, 'url' => $url])
|
||||
<div class="center">
|
||||
@isset($greeting)
|
||||
<p>{{ $greeting }}</p>
|
||||
|
@ -1,6 +1,7 @@
|
||||
@php
|
||||
$primary_color = isset($settings) ? $settings->primary_color : '#4caf50';
|
||||
$email_alignment = isset($settings) && $settings?->email_alignment ? $settings->email_alignment : 'center';
|
||||
$email_preferences = isset($url) && str_contains($url ?? '', '/#/') ? config('ninja.react_url').'/#/settings/user_details/notifications' : config('ninja.app_url');
|
||||
@endphp
|
||||
|
||||
<!DOCTYPE html
|
||||
@ -249,6 +250,13 @@
|
||||
<p style="text-align: center; color: #ffffff; font-size: 10px;
|
||||
font-family: Verdana, Geneva, Tahoma, sans-serif;">© {{ date('Y') }} Invoice Ninja, All Rights Reserved
|
||||
</p>
|
||||
|
||||
<a href="{{ $email_preferences }}">
|
||||
<p style="text-align: center; color: #ffffff; font-size: 10px; font-family: Verdana, Geneva, Tahoma, sans-serif;">
|
||||
{{ ctrans('texts.email_preferences') }}
|
||||
</p>
|
||||
</a>
|
||||
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
|
@ -45,6 +45,6 @@
|
||||
@endif
|
||||
@endisset
|
||||
|
||||
@isset($email_preferences)
|
||||
<p><a href="{!! $email_preferences !!}">{{ ctrans('texts.unsubscribe') }}</a></p>
|
||||
@endisset
|
||||
@if(isset($email_preferences) && $email_preferences)
|
||||
<p><a href="{!! $email_preferences !!}">{{ ctrans('texts.email_preferences') }}</a></p>
|
||||
@endif
|
@ -389,11 +389,11 @@
|
||||
</tr>
|
||||
<tr class="header-payment-due-label">
|
||||
<td>$payment_due_label:</td>
|
||||
<td>$payment_due</td>
|
||||
<td>$due_date</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="header-amount-due-label">$amount_due_label:</td>
|
||||
<td class="header-amount-due-value">$amount_due</td>
|
||||
<td class="header-amount-due-value">$balance_due</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
|
@ -64,7 +64,7 @@ class TaskImportTest extends TestCase
|
||||
2 => 'client.name',
|
||||
4 => 'task.number',
|
||||
5 => 'task.description',
|
||||
6 => 'task.is_billable',
|
||||
6 => 'task.billable',
|
||||
7 => 'task.start_date',
|
||||
9 => 'task.end_date',
|
||||
8 => 'task.start_time',
|
||||
@ -132,7 +132,7 @@ class TaskImportTest extends TestCase
|
||||
3 => 'project.name',
|
||||
2 => 'client.name',
|
||||
5 => 'task.description',
|
||||
6 => 'task.is_billable',
|
||||
6 => 'task.billable',
|
||||
7 => 'task.start_date',
|
||||
9 => 'task.end_date',
|
||||
8 => 'task.start_time',
|
||||
|
Loading…
x
Reference in New Issue
Block a user