mirror of
https://github.com/invoiceninja/invoiceninja.git
synced 2024-11-10 21:22:58 +01:00
Merge pull request #7428 from turbo124/v5-develop
Fixes for Client CSV Export
This commit is contained in:
commit
8d9683f633
@ -102,17 +102,9 @@ class CheckData extends Command
|
||||
config(['database.default' => $database]);
|
||||
}
|
||||
|
||||
$this->checkInvoiceBalances();
|
||||
$this->checkInvoiceBalancesNew();
|
||||
//$this->checkInvoicePayments();
|
||||
|
||||
//$this->checkPaidToDates();
|
||||
|
||||
$this->checkInvoiceBalances();
|
||||
$this->checkPaidToDatesNew();
|
||||
|
||||
// $this->checkPaidToCompanyDates();
|
||||
$this->checkClientBalances();
|
||||
|
||||
$this->checkContacts();
|
||||
$this->checkVendorContacts();
|
||||
$this->checkEntityInvitations();
|
||||
@ -123,7 +115,6 @@ class CheckData extends Command
|
||||
|
||||
if (! $this->option('client_id')) {
|
||||
$this->checkOAuth();
|
||||
//$this->checkFailedJobs();
|
||||
}
|
||||
|
||||
$this->logMessage('Done: '.strtoupper($this->isValid ? Account::RESULT_SUCCESS : Account::RESULT_FAILURE));
|
||||
@ -359,7 +350,6 @@ class CheckData extends Command
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private function checkEntityInvitations()
|
||||
{
|
||||
|
||||
@ -420,35 +410,6 @@ class CheckData extends Command
|
||||
|
||||
}
|
||||
|
||||
// private function checkPaidToCompanyDates()
|
||||
// {
|
||||
// Company::cursor()->each(function ($company){
|
||||
|
||||
// $payments = Payment::where('is_deleted', 0)
|
||||
// ->where('company_id', $company->id)
|
||||
// ->whereIn('status_id', [Payment::STATUS_COMPLETED, Payment:: STATUS_PENDING, Payment::STATUS_PARTIALLY_REFUNDED])
|
||||
// ->pluck('id');
|
||||
|
||||
// $unapplied = Payment::where('is_deleted', 0)
|
||||
// ->where('company_id', $company->id)
|
||||
// ->whereIn('status_id', [Payment::STATUS_COMPLETED, Payment:: STATUS_PENDING, Payment::STATUS_PARTIALLY_REFUNDED, Payment::STATUS_REFUNDED])
|
||||
// ->sum(\DB::Raw('amount - applied'));
|
||||
|
||||
// $paymentables = Paymentable::whereIn('payment_id', $payments)->sum(\DB::Raw('amount - refunded'));
|
||||
|
||||
// $client_paid_to_date = Client::where('company_id', $company->id)->where('is_deleted', 0)->withTrashed()->sum('paid_to_date');
|
||||
|
||||
// $total_payments = $paymentables + $unapplied;
|
||||
|
||||
// if (round($total_payments, 2) != round($client_paid_to_date, 2)) {
|
||||
// $this->wrong_paid_to_dates++;
|
||||
|
||||
// $this->logMessage($company->present()->name.' id = # '.$company->id." - Paid to date does not match Client Paid To Date = {$client_paid_to_date} - Invoice Payments = {$total_payments}");
|
||||
// }
|
||||
|
||||
// });
|
||||
|
||||
// }
|
||||
private function clientPaidToDateQuery()
|
||||
{
|
||||
$results = \DB::select( \DB::raw("
|
||||
@ -528,14 +489,11 @@ class CheckData extends Command
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
private function checkPaidToDates()
|
||||
{
|
||||
$this->wrong_paid_to_dates = 0;
|
||||
$credit_total_applied = 0;
|
||||
|
||||
|
||||
$clients = DB::table('clients')
|
||||
->leftJoin('payments', function($join) {
|
||||
$join->on('payments.client_id', '=', 'clients.id')
|
||||
@ -605,29 +563,6 @@ class CheckData extends Command
|
||||
$this->logMessage("{$this->wrong_paid_to_dates} clients with incorrect paid to dates");
|
||||
}
|
||||
|
||||
/*
|
||||
SELECT
|
||||
SUM(payments.applied) as payments_applied,
|
||||
SUM(invoices.amount - invoices.balance) as invoices_paid_amount,
|
||||
SUM(credits.amount - credits.balance) as credits_balance,
|
||||
SUM(invoices.balance) as invoices_balance,
|
||||
clients.id
|
||||
FROM payments
|
||||
JOIN clients
|
||||
ON clients.id = payments.client_id
|
||||
JOIN credits
|
||||
ON credits.client_id = clients.id
|
||||
JOIN invoices
|
||||
ON invoices.client_id = payments.client_id
|
||||
WHERE payments.is_deleted = 0
|
||||
AND payments.status_id IN (1,4,5,6)
|
||||
AND invoices.is_deleted = 0
|
||||
AND invoices.status_id != 1
|
||||
GROUP BY clients.id
|
||||
HAVING (payments_applied - credits_balance - invoices_balance) != invoices_paid_amount
|
||||
ORDER BY clients.id;
|
||||
*/
|
||||
|
||||
private function checkInvoicePayments()
|
||||
{
|
||||
$this->wrong_balances = 0;
|
||||
@ -660,33 +595,6 @@ ORDER BY clients.id;
|
||||
$this->logMessage("{$this->wrong_balances} clients with incorrect invoice balances");
|
||||
}
|
||||
|
||||
|
||||
|
||||
// $clients = DB::table('clients')
|
||||
// ->leftJoin('invoices', function($join){
|
||||
// $join->on('invoices.client_id', '=', 'clients.id')
|
||||
// ->where('invoices.is_deleted',0)
|
||||
// ->where('invoices.status_id', '>', 1);
|
||||
// })
|
||||
// ->leftJoin('credits', function($join){
|
||||
// $join->on('credits.client_id', '=', 'clients.id')
|
||||
// ->where('credits.is_deleted',0)
|
||||
// ->where('credits.status_id', '>', 1);
|
||||
// })
|
||||
// ->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.updated_at', '>', now()->subDays(2))
|
||||
// ->groupBy('clients.id')
|
||||
// ->havingRaw('sum(coalesce(invoices.amount - invoices.balance - credits.amount)) != sum(coalesce(payments.amount - payments.refunded, 0))')
|
||||
// ->get(['clients.id', DB::raw('sum(coalesce(invoices.amount - invoices.balance - credits.amount)) as invoice_amount'), DB::raw('sum(coalesce(payments.amount - payments.refunded, 0)) as payment_amount')]);
|
||||
|
||||
|
||||
|
||||
|
||||
private function clientBalanceQuery()
|
||||
{
|
||||
$results = \DB::select( \DB::raw("
|
||||
@ -708,9 +616,6 @@ ORDER BY clients.id;
|
||||
return $results;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
private function checkClientBalances()
|
||||
{
|
||||
$this->wrong_balances = 0;
|
||||
@ -722,66 +627,30 @@ ORDER BY clients.id;
|
||||
{
|
||||
$client = (array)$client;
|
||||
|
||||
$invoice_balance = $client['invoice_balance'];
|
||||
|
||||
// $ledger = CompanyLedger::where('client_id', $client['client_id'])->orderBy('id', 'DESC')->first();
|
||||
|
||||
if ((string) $invoice_balance != (string) $client['client_balance']) {
|
||||
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 = {$invoice_balance} - Client Balance = ".rtrim($client['client_balance'], '0'));
|
||||
$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('ledger_balance')){
|
||||
if($this->option('client_balance')){
|
||||
|
||||
$this->logMessage("# {$client_object->id} " . $client_object->present()->name.' - '.$client_object->number." Fixing {$client_object->balance} to {$invoice_balance}");
|
||||
$client_object->balance = $invoice_balance;
|
||||
$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();
|
||||
|
||||
// $ledger->adjustment = $invoice_balance;
|
||||
// $ledger->balance = $invoice_balance;
|
||||
// $ledger->notes = 'Ledger Adjustment';
|
||||
// $ledger->save();
|
||||
}
|
||||
|
||||
|
||||
$this->isValid = false;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// foreach (Client::cursor()->where('is_deleted', 0)->where('clients.updated_at', '>', now()->subDays(2)) as $client) {
|
||||
|
||||
// $invoice_balance = Invoice::where('client_id', $client->id)->where('is_deleted', false)->where('status_id', '>', 1)->withTrashed()->sum('balance');
|
||||
// $credit_balance = Credit::where('client_id', $client->id)->where('is_deleted', false)->withTrashed()->sum('balance');
|
||||
|
||||
// if($client->balance != $invoice_balance)
|
||||
// $invoice_balance -= $credit_balance;
|
||||
|
||||
// $ledger = CompanyLedger::where('client_id', $client->id)->orderBy('id', 'DESC')->first();
|
||||
|
||||
// if ($ledger && (string) $invoice_balance != (string) $client->balance) {
|
||||
// $this->wrong_paid_to_dates++;
|
||||
// $this->logMessage($client->present()->name.' - '.$client->id." - calculated client balances do not match Invoice Balances = {$invoice_balance} - Client Balance = ".rtrim($client->balance, '0'). " Ledger balance = {$ledger->balance}");
|
||||
|
||||
// $this->isValid = false;
|
||||
|
||||
// }
|
||||
// }
|
||||
|
||||
$this->logMessage("{$this->wrong_paid_to_dates} clients with incorrect client balances");
|
||||
}
|
||||
|
||||
//fix for client balances =
|
||||
//$adjustment = ($invoice_balance-$client->balance)
|
||||
//$client->balance += $adjustment;
|
||||
|
||||
//$ledger_adjustment = $ledger->balance - $client->balance;
|
||||
//$ledger->balance += $ledger_adjustment
|
||||
|
||||
private function invoiceBalanceQuery()
|
||||
{
|
||||
$results = \DB::select( \DB::raw("
|
||||
@ -803,7 +672,7 @@ ORDER BY clients.id;
|
||||
return $results;
|
||||
}
|
||||
|
||||
private function checkInvoiceBalancesNew()
|
||||
private function checkInvoiceBalances()
|
||||
{
|
||||
$this->wrong_balances = 0;
|
||||
$this->wrong_paid_to_dates = 0;
|
||||
@ -818,25 +687,30 @@ ORDER BY clients.id;
|
||||
|
||||
$ledger = CompanyLedger::where('client_id', $client->id)->orderBy('id', 'DESC')->first();
|
||||
|
||||
if ($ledger && number_format($invoice_balance, 4) != number_format($client->balance, 4)) {
|
||||
if (number_format($invoice_balance, 4) != number_format($client->balance, 4)) {
|
||||
$this->wrong_balances++;
|
||||
$this->logMessage("# {$client->id} " . $client->present()->name.' - '.$client->number." - Balance Failure - Invoice Balances = {$invoice_balance} Client Balance = {$client->balance} Ledger Balance = {$ledger->balance}");
|
||||
$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->isValid = false;
|
||||
|
||||
|
||||
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)))
|
||||
{
|
||||
$ledger->adjustment = $invoice_balance;
|
||||
$ledger->balance = $invoice_balance;
|
||||
$ledger->notes = 'Ledger Adjustment';
|
||||
$ledger->save();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@ -844,7 +718,7 @@ ORDER BY clients.id;
|
||||
|
||||
}
|
||||
|
||||
private function checkInvoiceBalances()
|
||||
private function checkLedgerBalances()
|
||||
{
|
||||
$this->wrong_balances = 0;
|
||||
$this->wrong_paid_to_dates = 0;
|
||||
@ -880,26 +754,6 @@ ORDER BY clients.id;
|
||||
|
||||
private function checkLogoFiles()
|
||||
{
|
||||
// $accounts = DB::table('accounts')
|
||||
// ->where('logo', '!=', '')
|
||||
// ->orderBy('id')
|
||||
// ->get(['logo']);
|
||||
|
||||
// $countMissing = 0;
|
||||
|
||||
// foreach ($accounts as $account) {
|
||||
// $path = public_path('logo/' . $account->logo);
|
||||
// if (! file_exists($path)) {
|
||||
// $this->logMessage('Missing file: ' . $account->logo);
|
||||
// $countMissing++;
|
||||
// }
|
||||
// }
|
||||
|
||||
// if ($countMissing > 0) {
|
||||
// $this->isValid = false;
|
||||
// }
|
||||
|
||||
// $this->logMessage($countMissing . ' missing logo files');
|
||||
}
|
||||
|
||||
/**
|
||||
@ -985,60 +839,21 @@ ORDER BY clients.id;
|
||||
{
|
||||
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();
|
||||
|
||||
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)
|
||||
$this->logMessage("I found a payment for {$account->key}");
|
||||
$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)
|
||||
$this->logMessage("I found a payment for {$account->key}");
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/* //used to set a company owner on the company_users table
|
||||
|
||||
$c = Company::whereDoesntHave('company_users', function ($query){
|
||||
$query->where('is_owner', true)->withTrashed();
|
||||
})->cursor()->each(function ($company){
|
||||
|
||||
if(!$company->company_users()->exists()){
|
||||
echo "No company users AT ALL {$company->id}\n";
|
||||
|
||||
}
|
||||
else{
|
||||
|
||||
$cu = $company->company_users()->orderBy('id', 'ASC')->orderBy('is_admin', 'ASC')->first();
|
||||
echo "{$company->id} - {$cu->id} \n";
|
||||
$cu->is_owner=true;
|
||||
$cu->save();
|
||||
|
||||
}
|
||||
});
|
||||
*/
|
||||
|
||||
/* query if we want to company company ledger to client balance
|
||||
$results = \DB::select( \DB::raw("
|
||||
SELECT
|
||||
clients.id as client_id,
|
||||
clients.balance as client_balance
|
||||
from clients,
|
||||
(select max(company_ledgers.id) as cid, company_ledgers.client_id as client_id, company_ledgers.balance as balance
|
||||
FROM company_ledgers) ledger
|
||||
where clients.id=ledger.client_id
|
||||
AND clients.balance != ledger.balance
|
||||
GROUP BY clients.id
|
||||
ORDER BY clients.id;
|
||||
") );
|
||||
*/
|
||||
}
|
@ -131,6 +131,7 @@ class DemoMode extends Command
|
||||
'enabled_modules' => 32767,
|
||||
'company_key' => 'KEY',
|
||||
'enable_shop_api' => true,
|
||||
'markdown_email_enabled' => false,
|
||||
]);
|
||||
|
||||
$settings = $company->settings;
|
||||
|
@ -70,6 +70,7 @@ class BaseExport
|
||||
$header = [];
|
||||
|
||||
foreach($this->input['report_keys'] as $value){
|
||||
|
||||
$key = array_search ($value, $this->entity_keys);
|
||||
|
||||
$key = str_replace("item.", "", $key);
|
||||
@ -77,7 +78,6 @@ class BaseExport
|
||||
$key = str_replace("client.", "", $key);
|
||||
$key = str_replace("contact.", "", $key);
|
||||
|
||||
|
||||
$header[] = ctrans("texts.{$key}");
|
||||
}
|
||||
|
||||
|
@ -54,7 +54,7 @@ class ClientExport extends BaseExport
|
||||
'name' => 'client.name',
|
||||
'number' => 'client.number',
|
||||
'paid_to_date' => 'client.paid_to_date',
|
||||
'phone' => 'client.phone',
|
||||
'client_phone' => 'client.phone',
|
||||
'postal_code' => 'client.postal_code',
|
||||
'private_notes' => 'client.private_notes',
|
||||
'public_notes' => 'client.public_notes',
|
||||
@ -70,7 +70,7 @@ class ClientExport extends BaseExport
|
||||
'currency' => 'client.currency',
|
||||
'first_name' => 'contact.first_name',
|
||||
'last_name' => 'contact.last_name',
|
||||
'phone' => 'contact.phone',
|
||||
'contact_phone' => 'contact.phone',
|
||||
'contact_custom_value1' => 'contact.custom_value1',
|
||||
'contact_custom_value2' => 'contact.custom_value2',
|
||||
'contact_custom_value3' => 'contact.custom_value3',
|
||||
@ -78,46 +78,6 @@ class ClientExport extends BaseExport
|
||||
'email' => 'contact.email',
|
||||
];
|
||||
|
||||
protected array $all_keys = [
|
||||
'client.address1',
|
||||
'client.address2',
|
||||
'client.balance',
|
||||
'client.city',
|
||||
'client.country_id',
|
||||
'client.credit_balance',
|
||||
'client.custom_value1',
|
||||
'client.custom_value2',
|
||||
'client.custom_value3',
|
||||
'client.custom_value4',
|
||||
'client.id_number',
|
||||
'client.industry_id',
|
||||
'client.last_login',
|
||||
'client.name',
|
||||
'client.number',
|
||||
'client.paid_to_date',
|
||||
'client.phone',
|
||||
'client.postal_code',
|
||||
'client.private_notes',
|
||||
'client.public_notes',
|
||||
'client.shipping_address1',
|
||||
'client.shipping_address2',
|
||||
'client.shipping_city',
|
||||
'client.shipping_country_id',
|
||||
'client.shipping_postal_code',
|
||||
'client.shipping_state',
|
||||
'client.state',
|
||||
'client.vat_number',
|
||||
'client.website',
|
||||
'client.currency',
|
||||
'contact.first_name',
|
||||
'contact.last_name',
|
||||
'contact.phone',
|
||||
'contact.custom_value1',
|
||||
'contact.custom_value2',
|
||||
'contact.custom_value3',
|
||||
'contact.custom_value4',
|
||||
'contact.email',
|
||||
];
|
||||
private array $decorate_keys = [
|
||||
'client.country_id',
|
||||
'client.shipping_country_id',
|
||||
@ -146,7 +106,7 @@ class ClientExport extends BaseExport
|
||||
$this->csv = Writer::createFromString();
|
||||
|
||||
if(count($this->input['report_keys']) == 0)
|
||||
$this->input['report_keys'] = $this->all_keys;
|
||||
$this->input['report_keys'] = array_values($this->entity_keys);
|
||||
|
||||
//insert the header
|
||||
$this->csv->insertOne($this->buildHeader());
|
||||
@ -178,20 +138,22 @@ class ClientExport extends BaseExport
|
||||
if($contact = $client->contacts()->first())
|
||||
$transformed_contact = $this->contact_transformer->transform($contact);
|
||||
|
||||
|
||||
$entity = [];
|
||||
|
||||
foreach(array_values($this->input['report_keys']) as $key){
|
||||
|
||||
$parts = explode(".",$key);
|
||||
$entity[$parts[1]] = "";
|
||||
|
||||
$keyval = array_search($key, $this->entity_keys);
|
||||
|
||||
if($parts[0] == 'client' && array_key_exists($parts[1], $transformed_client)) {
|
||||
$entity[$parts[1]] = $transformed_client[$parts[1]];
|
||||
$entity[$keyval] = $transformed_client[$parts[1]];
|
||||
}
|
||||
elseif($parts[0] == 'contact' && array_key_exists($parts[1], $transformed_client)) {
|
||||
$entity[$parts[1]] = $transformed_contact[$parts[1]];
|
||||
elseif($parts[0] == 'contact' && array_key_exists($parts[1], $transformed_contact)) {
|
||||
$entity[$keyval] = $transformed_contact[$parts[1]];
|
||||
}
|
||||
else
|
||||
$entity[$keyval] = "";
|
||||
|
||||
}
|
||||
|
||||
@ -202,16 +164,16 @@ class ClientExport extends BaseExport
|
||||
private function decorateAdvancedFields(Client $client, array $entity) :array
|
||||
{
|
||||
|
||||
if(in_array('country_id', $this->input['report_keys']))
|
||||
$entity['country_id'] = $client->country ? ctrans("texts.country_{$client->country->name}") : "";
|
||||
if(in_array('client.country_id', $this->input['report_keys']))
|
||||
$entity['country'] = $client->country ? ctrans("texts.country_{$client->country->name}") : "";
|
||||
|
||||
if(in_array('shipping_country_id', $this->input['report_keys']))
|
||||
$entity['shipping_country_id'] = $client->shipping_country ? ctrans("texts.country_{$client->shipping_country->name}") : "";
|
||||
if(in_array('client.shipping_country_id', $this->input['report_keys']))
|
||||
$entity['shipping_country'] = $client->shipping_country ? ctrans("texts.country_{$client->shipping_country->name}") : "";
|
||||
|
||||
if(in_array('currency', $this->input['report_keys']))
|
||||
$entity['currency_id'] = $client->currency() ? $client->currency()->code : $client->company->currency()->code;
|
||||
if(in_array('client.currency', $this->input['report_keys']))
|
||||
$entity['currency'] = $client->currency() ? $client->currency()->code : $client->company->currency()->code;
|
||||
|
||||
if(in_array('industry_id', $this->input['report_keys']))
|
||||
if(in_array('client.industry_id', $this->input['report_keys']))
|
||||
$entity['industry_id'] = $client->industry ? ctrans("texts.industry_{$client->industry->name}") : "";
|
||||
|
||||
return $entity;
|
||||
|
@ -50,7 +50,7 @@ class ContactExport extends BaseExport
|
||||
'name' => 'client.name',
|
||||
'number' => 'client.number',
|
||||
'paid_to_date' => 'client.paid_to_date',
|
||||
'phone' => 'client.phone',
|
||||
'client_phone' => 'client.phone',
|
||||
'postal_code' => 'client.postal_code',
|
||||
'private_notes' => 'client.private_notes',
|
||||
'public_notes' => 'client.public_notes',
|
||||
@ -66,7 +66,7 @@ class ContactExport extends BaseExport
|
||||
'currency' => 'client.currency',
|
||||
'first_name' => 'contact.first_name',
|
||||
'last_name' => 'contact.last_name',
|
||||
'phone' => 'contact.phone',
|
||||
'contact_phone' => 'contact.phone',
|
||||
'contact_custom_value1' => 'contact.custom_value1',
|
||||
'contact_custom_value2' => 'contact.custom_value2',
|
||||
'contact_custom_value3' => 'contact.custom_value3',
|
||||
@ -74,49 +74,6 @@ class ContactExport extends BaseExport
|
||||
'email' => 'contact.email',
|
||||
];
|
||||
|
||||
|
||||
protected array $all_keys = [
|
||||
'client.address1',
|
||||
'client.address2',
|
||||
'client.balance',
|
||||
'client.city',
|
||||
'client.country_id',
|
||||
'client.credit_balance',
|
||||
'client.custom_value1',
|
||||
'client.custom_value2',
|
||||
'client.custom_value3',
|
||||
'client.custom_value4',
|
||||
'client.id_number',
|
||||
'client.industry_id',
|
||||
'client.last_login',
|
||||
'client.name',
|
||||
'client.number',
|
||||
'client.paid_to_date',
|
||||
'client.phone',
|
||||
'client.postal_code',
|
||||
'client.private_notes',
|
||||
'client.public_notes',
|
||||
'client.shipping_address1',
|
||||
'client.shipping_address2',
|
||||
'client.shipping_city',
|
||||
'client.shipping_country_id',
|
||||
'client.shipping_postal_code',
|
||||
'client.shipping_state',
|
||||
'client.state',
|
||||
'client.vat_number',
|
||||
'client.website',
|
||||
'client.currency',
|
||||
'contact.first_name',
|
||||
'contact.last_name',
|
||||
'contact.phone',
|
||||
'contact.custom_value1',
|
||||
'contact.custom_value2',
|
||||
'contact.custom_value3',
|
||||
'contact.custom_value4',
|
||||
'contact.email',
|
||||
];
|
||||
|
||||
|
||||
private array $decorate_keys = [
|
||||
'client.country_id',
|
||||
'client.shipping_country_id',
|
||||
@ -145,7 +102,7 @@ class ContactExport extends BaseExport
|
||||
$this->csv = Writer::createFromString();
|
||||
|
||||
if(count($this->input['report_keys']) == 0)
|
||||
$this->input['report_keys'] = $this->all_keys;
|
||||
$this->input['report_keys'] = array_values($this->entity_keys);
|
||||
|
||||
//insert the header
|
||||
$this->csv->insertOne($this->buildHeader());
|
||||
@ -178,15 +135,16 @@ class ContactExport extends BaseExport
|
||||
foreach(array_values($this->input['report_keys']) as $key){
|
||||
|
||||
$parts = explode(".",$key);
|
||||
$entity[$parts[1]] = "";
|
||||
$keyval = array_search($key, $this->entity_keys);
|
||||
|
||||
if($parts[0] == 'client') {
|
||||
$entity[$parts[1]] = $transformed_client[$parts[1]];
|
||||
if($parts[0] == 'client' && array_key_exists($parts[1], $transformed_client)) {
|
||||
$entity[$keyval] = $transformed_client[$parts[1]];
|
||||
}
|
||||
elseif($parts[0] == 'contact') {
|
||||
$entity[$parts[1]] = $transformed_contact[$parts[1]];
|
||||
elseif($parts[0] == 'contact' && array_key_exists($parts[1], $transformed_contact)) {
|
||||
$entity[$keyval] = $transformed_contact[$parts[1]];
|
||||
}
|
||||
|
||||
else
|
||||
$entity[$keyval] = "";
|
||||
}
|
||||
|
||||
return $this->decorateAdvancedFields($contact->client, $entity);
|
||||
@ -196,16 +154,16 @@ class ContactExport extends BaseExport
|
||||
private function decorateAdvancedFields(Client $client, array $entity) :array
|
||||
{
|
||||
|
||||
if(array_key_exists('country_id', $entity))
|
||||
$entity['country_id'] = $client->country ? ctrans("texts.country_{$client->country->name}") : "";
|
||||
if(in_array('client.country_id', $this->input['report_keys']))
|
||||
$entity['country'] = $client->country ? ctrans("texts.country_{$client->country->name}") : "";
|
||||
|
||||
if(array_key_exists('shipping_country_id', $entity))
|
||||
$entity['shipping_country_id'] = $client->shipping_country ? ctrans("texts.country_{$client->shipping_country->name}") : "";
|
||||
if(in_array('client.shipping_country_id', $this->input['report_keys']))
|
||||
$entity['shipping_country'] = $client->shipping_country ? ctrans("texts.country_{$client->shipping_country->name}") : "";
|
||||
|
||||
if(array_key_exists('currency', $entity))
|
||||
$entity['currency'] = $client->currency()->code;
|
||||
if(in_array('client.currency', $this->input['report_keys']))
|
||||
$entity['currency'] = $client->currency() ? $client->currency()->code : $client->company->currency()->code;
|
||||
|
||||
if(array_key_exists('industry_id', $entity))
|
||||
if(in_array('client.industry_id', $this->input['report_keys']))
|
||||
$entity['industry_id'] = $client->industry ? ctrans("texts.industry_{$client->industry->name}") : "";
|
||||
|
||||
return $entity;
|
||||
|
@ -68,45 +68,6 @@ class CreditExport extends BaseExport
|
||||
'currency' => 'currency'
|
||||
];
|
||||
|
||||
protected array $all_keys = [
|
||||
'amount',
|
||||
'balance',
|
||||
'client_id',
|
||||
'custom_surcharge1',
|
||||
'custom_surcharge2',
|
||||
'custom_surcharge3',
|
||||
'custom_surcharge4',
|
||||
'country_id',
|
||||
'custom_value1',
|
||||
'custom_value2',
|
||||
'custom_value3',
|
||||
'custom_value4',
|
||||
'date',
|
||||
'discount',
|
||||
'due_date',
|
||||
'exchange_rate',
|
||||
'footer',
|
||||
'invoice_id',
|
||||
'number',
|
||||
'paid_to_date',
|
||||
'partial',
|
||||
'partial_due_date',
|
||||
'po_number',
|
||||
'private_notes',
|
||||
'public_notes',
|
||||
'status_id',
|
||||
'tax_name1',
|
||||
'tax_name2',
|
||||
'tax_name3',
|
||||
'tax_rate1',
|
||||
'tax_rate2',
|
||||
'tax_rate3',
|
||||
'terms',
|
||||
'total_taxes',
|
||||
'currency'
|
||||
];
|
||||
|
||||
|
||||
private array $decorate_keys = [
|
||||
'country',
|
||||
'client',
|
||||
@ -133,12 +94,12 @@ class CreditExport extends BaseExport
|
||||
//load the CSV document from a string
|
||||
$this->csv = Writer::createFromString();
|
||||
|
||||
if(count($this->input['report_keys']) == 0)
|
||||
$this->input['report_keys'] = array_values($this->entity_keys);
|
||||
|
||||
//insert the header
|
||||
$this->csv->insertOne($this->buildHeader());
|
||||
|
||||
if(count($this->input['report_keys']) == 0)
|
||||
$this->input['report_keys'] = $this->all_keys;
|
||||
|
||||
$query = Credit::query()
|
||||
->withTrashed()
|
||||
->with('client')->where('company_id', $this->company->id)
|
||||
@ -166,7 +127,13 @@ class CreditExport extends BaseExport
|
||||
|
||||
foreach(array_values($this->input['report_keys']) as $key){
|
||||
|
||||
$entity[$key] = $transformed_credit[$key];
|
||||
$keyval = array_search($key, $this->entity_keys);
|
||||
|
||||
if(array_key_exists($key, $transformed_credit))
|
||||
$entity[$keyval] = $transformed_credit[$key];
|
||||
else
|
||||
$entity[$keyval] = '';
|
||||
|
||||
}
|
||||
|
||||
return $this->decorateAdvancedFields($credit, $entity);
|
||||
@ -176,17 +143,20 @@ class CreditExport extends BaseExport
|
||||
private function decorateAdvancedFields(Credit $credit, array $entity) :array
|
||||
{
|
||||
|
||||
if(array_key_exists('country_id', $entity))
|
||||
$entity['country_id'] = $credit->client->country ? ctrans("texts.country_{$credit->client->country->name}") : "";
|
||||
if(in_array('country_id', $this->input['report_keys']))
|
||||
$entity['country'] = $credit->client->country ? ctrans("texts.country_{$credit->client->country->name}") : "";
|
||||
|
||||
if(array_key_exists('currency', $entity))
|
||||
$entity['currency'] = $credit->client->currency()->code;
|
||||
if(in_array('currency_id', $this->input['report_keys']))
|
||||
$entity['currency_id'] = $credit->client->currency() ? $credit->client->currency()->code : $invoice->company->currency()->code;;
|
||||
|
||||
if(array_key_exists('invoice_id', $entity))
|
||||
$entity['invoice_id'] = $credit->invoice ? $credit->invoice->number : "";
|
||||
if(in_array('invoice_id', $this->input['report_keys']))
|
||||
$entity['invoice'] = $credit->invoice ? $credit->invoice->number : "";
|
||||
|
||||
if(array_key_exists('client_id', $entity))
|
||||
$entity['client_id'] = $credit->client->present()->name();
|
||||
if(in_array('client_id', $this->input['report_keys']))
|
||||
$entity['client'] = $credit->client->present()->name();
|
||||
|
||||
if(in_array('status_id',$this->input['report_keys']))
|
||||
$entity['status'] = $credit->stringStatus($credit->status_id);
|
||||
|
||||
return $entity;
|
||||
}
|
||||
|
@ -33,20 +33,12 @@ class DocumentExport extends BaseExport
|
||||
|
||||
protected array $entity_keys = [
|
||||
'record_type' => 'record_type',
|
||||
'record_name' => 'record_name',
|
||||
// 'record_name' => 'record_name',
|
||||
'name' => 'name',
|
||||
'type' => 'type',
|
||||
'created_at' => 'created_at',
|
||||
];
|
||||
|
||||
protected array $all_keys = [
|
||||
'record_type',
|
||||
'record_name',
|
||||
'name',
|
||||
'type',
|
||||
'created_at',
|
||||
];
|
||||
|
||||
private array $decorate_keys = [
|
||||
|
||||
];
|
||||
@ -71,7 +63,7 @@ class DocumentExport extends BaseExport
|
||||
$this->csv = Writer::createFromString();
|
||||
|
||||
if(count($this->input['report_keys']) == 0)
|
||||
$this->input['report_keys'] = $this->all_keys;
|
||||
$this->input['report_keys'] = array_values($this->entity_keys);
|
||||
|
||||
//insert the header
|
||||
$this->csv->insertOne($this->buildHeader());
|
||||
@ -100,8 +92,12 @@ class DocumentExport extends BaseExport
|
||||
|
||||
foreach(array_values($this->input['report_keys']) as $key){
|
||||
|
||||
$entity[$key] = $transformed_entity[$key];
|
||||
|
||||
$keyval = array_search($key, $this->entity_keys);
|
||||
|
||||
if(array_key_exists($key, $transformed_entity))
|
||||
$entity[$keyval] = $transformed_entity[$key];
|
||||
else
|
||||
$entity[$keyval] = '';
|
||||
}
|
||||
|
||||
return $this->decorateAdvancedFields($document, $entity);
|
||||
@ -111,11 +107,11 @@ class DocumentExport extends BaseExport
|
||||
private function decorateAdvancedFields(Document $document, array $entity) :array
|
||||
{
|
||||
|
||||
if(array_key_exists('record_type', $entity))
|
||||
if(in_array('record_type', $this->input['report_keys']))
|
||||
$entity['record_type'] = class_basename($document->documentable);
|
||||
|
||||
if(array_key_exists('record_name', $entity))
|
||||
$entity['record_name'] = $document->hashed_id;
|
||||
// if(in_array('record_name', $this->input['report_keys']))
|
||||
// $entity['record_name'] = $document->hashed_id;
|
||||
|
||||
return $entity;
|
||||
}
|
||||
|
@ -63,40 +63,6 @@ class ExpenseExport extends BaseExport
|
||||
'invoice' => 'invoice_id',
|
||||
];
|
||||
|
||||
protected array $all_keys = [
|
||||
'amount',
|
||||
'category_id',
|
||||
'client_id',
|
||||
'custom_value1',
|
||||
'custom_value2',
|
||||
'custom_value3',
|
||||
'custom_value4',
|
||||
'currency_id',
|
||||
'date',
|
||||
'exchange_rate',
|
||||
'foreign_amount',
|
||||
'invoice_currency_id',
|
||||
'payment_date',
|
||||
'number',
|
||||
'payment_type_id',
|
||||
'private_notes',
|
||||
'project_id',
|
||||
'public_notes',
|
||||
'tax_amount1',
|
||||
'tax_amount2',
|
||||
'tax_amount3',
|
||||
'tax_name1',
|
||||
'tax_name2',
|
||||
'tax_name3',
|
||||
'tax_rate1',
|
||||
'tax_rate2',
|
||||
'tax_rate3',
|
||||
'transaction_reference',
|
||||
'vendor_id',
|
||||
'invoice_id',
|
||||
];
|
||||
|
||||
|
||||
private array $decorate_keys = [
|
||||
'client',
|
||||
'currency',
|
||||
@ -127,7 +93,7 @@ class ExpenseExport extends BaseExport
|
||||
$this->csv = Writer::createFromString();
|
||||
|
||||
if(count($this->input['report_keys']) == 0)
|
||||
$this->input['report_keys'] = $this->all_keys;
|
||||
$this->input['report_keys'] = array_values($this->entity_keys);
|
||||
|
||||
//insert the header
|
||||
$this->csv->insertOne($this->buildHeader());
|
||||
@ -161,7 +127,13 @@ class ExpenseExport extends BaseExport
|
||||
|
||||
foreach(array_values($this->input['report_keys']) as $key){
|
||||
|
||||
$entity[$key] = $transformed_expense[$key];
|
||||
$keyval = array_search($key, $this->entity_keys);
|
||||
|
||||
if(array_key_exists($key, $transformed_expense))
|
||||
$entity[$keyval] = $transformed_expense[$key];
|
||||
else
|
||||
$entity[$keyval] = '';
|
||||
|
||||
}
|
||||
|
||||
return $this->decorateAdvancedFields($expense, $entity);
|
||||
@ -170,26 +142,26 @@ class ExpenseExport extends BaseExport
|
||||
|
||||
private function decorateAdvancedFields(Expense $expense, array $entity) :array
|
||||
{
|
||||
if(array_key_exists('currency_id', $entity))
|
||||
$entity['currency_id'] = $expense->currency ? $expense->currency->code : "";
|
||||
if(in_array('currency_id', $this->input['report_keys']))
|
||||
$entity['currency'] = $expense->currency ? $expense->currency->code : "";
|
||||
|
||||
if(array_key_exists('client_id', $entity))
|
||||
$entity['client_id'] = $expense->client ? $expense->client->present()->name() : "";
|
||||
if(in_array('client_id', $this->input['report_keys']))
|
||||
$entity['client'] = $expense->client ? $expense->client->present()->name() : "";
|
||||
|
||||
if(array_key_exists('invoice_id', $entity))
|
||||
$entity['invoice_id'] = $expense->invoice ? $expense->invoice->number : "";
|
||||
if(in_array('invoice_id', $this->input['report_keys']))
|
||||
$entity['invoice'] = $expense->invoice ? $expense->invoice->number : "";
|
||||
|
||||
if(array_key_exists('category_id', $entity))
|
||||
$entity['category_id'] = $expense->category ? $expense->category->name : "";
|
||||
if(in_array('category_id', $this->input['report_keys']))
|
||||
$entity['category'] = $expense->category ? $expense->category->name : "";
|
||||
|
||||
if(array_key_exists('vendor_id', $entity))
|
||||
$entity['vendor_id'] = $expense->vendor ? $expense->vendor->name : "";
|
||||
if(in_array('vendor_id', $this->input['report_keys']))
|
||||
$entity['vendor'] = $expense->vendor ? $expense->vendor->name : "";
|
||||
|
||||
if(array_key_exists('payment_type_id', $entity))
|
||||
$entity['payment_type_id'] = $expense->payment_type ? $expense->payment_type->name : "";
|
||||
if(in_array('payment_type_id', $this->input['report_keys']))
|
||||
$entity['payment_type'] = $expense->payment_type ? $expense->payment_type->name : "";
|
||||
|
||||
if(array_key_exists('project_id', $entity))
|
||||
$entity['project_id'] = $expense->project ? $expense->project->name : "";
|
||||
if(in_array('project_id', $this->input['report_keys']))
|
||||
$entity['project'] = $expense->project ? $expense->project->name : "";
|
||||
|
||||
|
||||
return $entity;
|
||||
|
@ -66,48 +66,13 @@ class InvoiceExport extends BaseExport
|
||||
'currency_id' => 'currency_id'
|
||||
];
|
||||
|
||||
|
||||
protected array $all_keys = [
|
||||
'amount',
|
||||
'balance',
|
||||
'client_id',
|
||||
'custom_surcharge1',
|
||||
'custom_surcharge2',
|
||||
'custom_surcharge3',
|
||||
'custom_surcharge4',
|
||||
'custom_value1',
|
||||
'custom_value2',
|
||||
'custom_value3',
|
||||
'custom_value4',
|
||||
'date',
|
||||
'discount',
|
||||
'due_date',
|
||||
'exchange_rate',
|
||||
'footer',
|
||||
'number',
|
||||
'paid_to_date',
|
||||
'partial',
|
||||
'partial_due_date',
|
||||
'po_number',
|
||||
'private_notes',
|
||||
'public_notes',
|
||||
'status_id',
|
||||
'tax_name1',
|
||||
'tax_name2',
|
||||
'tax_name3',
|
||||
'tax_rate1',
|
||||
'tax_rate2',
|
||||
'tax_rate3',
|
||||
'terms',
|
||||
'total_taxes',
|
||||
'currency_id',
|
||||
];
|
||||
|
||||
private array $decorate_keys = [
|
||||
'country',
|
||||
'client',
|
||||
'currency_id',
|
||||
'status',
|
||||
'vendor',
|
||||
'project',
|
||||
];
|
||||
|
||||
public function __construct(Company $company, array $input)
|
||||
@ -130,14 +95,15 @@ class InvoiceExport extends BaseExport
|
||||
$this->csv = Writer::createFromString();
|
||||
|
||||
if(count($this->input['report_keys']) == 0)
|
||||
$this->input['report_keys'] = $this->all_keys;
|
||||
$this->input['report_keys'] = array_values($this->entity_keys);
|
||||
|
||||
//insert the header
|
||||
$this->csv->insertOne($this->buildHeader());
|
||||
|
||||
$query = Invoice::query()
|
||||
->withTrashed()
|
||||
->with('client')->where('company_id', $this->company->id)
|
||||
->with('client')
|
||||
->where('company_id', $this->company->id)
|
||||
->where('is_deleted',0);
|
||||
|
||||
$query = $this->addDateRange($query);
|
||||
@ -162,8 +128,12 @@ class InvoiceExport extends BaseExport
|
||||
|
||||
foreach(array_values($this->input['report_keys']) as $key){
|
||||
|
||||
if(array_key_exists($key, $transformed_invoice))
|
||||
$entity[$key] = $transformed_invoice[$key];
|
||||
$keyval = array_search($key, $this->entity_keys);
|
||||
|
||||
if(array_key_exists($key, $transformed_invoice))
|
||||
$entity[$keyval] = $transformed_invoice[$key];
|
||||
else
|
||||
$entity[$keyval] = '';
|
||||
}
|
||||
|
||||
return $this->decorateAdvancedFields($invoice, $entity);
|
||||
@ -172,14 +142,17 @@ class InvoiceExport extends BaseExport
|
||||
|
||||
private function decorateAdvancedFields(Invoice $invoice, array $entity) :array
|
||||
{
|
||||
if(in_array('currency_id',$this->input['report_keys']))
|
||||
$entity['currency_id'] = $invoice->client->currency()->code ?: $invoice->company->currency()->code;
|
||||
if(in_array('country_id', $this->input['report_keys']))
|
||||
$entity['country'] = $invoice->client->country ? ctrans("texts.country_{$invoice->client->country->name}") : "";
|
||||
|
||||
if(in_array('client_id',$this->input['report_keys']))
|
||||
$entity['client_id'] = $invoice->client->present()->name();
|
||||
if(in_array('currency_id', $this->input['report_keys']))
|
||||
$entity['currency_id'] = $invoice->client->currency() ? $invoice->client->currency()->code : $invoice->company->currency()->code;
|
||||
|
||||
if(in_array('client_id', $this->input['report_keys']))
|
||||
$entity['client'] = $invoice->client->present()->name();
|
||||
|
||||
if(in_array('status_id',$this->input['report_keys']))
|
||||
$entity['status_id'] = $invoice->stringStatus($invoice->status_id);
|
||||
$entity['status'] = $invoice->stringStatus($invoice->status_id);
|
||||
|
||||
return $entity;
|
||||
}
|
||||
|
@ -64,7 +64,7 @@ class InvoiceItemExport extends BaseExport
|
||||
'terms' => 'terms',
|
||||
'total_taxes' => 'total_taxes',
|
||||
'currency' => 'currency_id',
|
||||
'qty' => 'item.quantity',
|
||||
'quantity' => 'item.quantity',
|
||||
'unit_cost' => 'item.cost',
|
||||
'product_key' => 'item.product_key',
|
||||
'cost' => 'item.product_cost',
|
||||
@ -85,64 +85,9 @@ class InvoiceItemExport extends BaseExport
|
||||
'invoice4' => 'item.custom_value4',
|
||||
];
|
||||
|
||||
protected array $all_keys = [
|
||||
'amount',
|
||||
'balance',
|
||||
'client_id',
|
||||
'custom_surcharge1',
|
||||
'custom_surcharge2',
|
||||
'custom_surcharge3',
|
||||
'custom_surcharge4',
|
||||
'custom_value1',
|
||||
'custom_value2',
|
||||
'custom_value3',
|
||||
'custom_value4',
|
||||
'date',
|
||||
'discount',
|
||||
'due_date',
|
||||
'exchange_rate',
|
||||
'footer',
|
||||
'number',
|
||||
'paid_to_date',
|
||||
'partial',
|
||||
'partial_due_date',
|
||||
'po_number',
|
||||
'private_notes',
|
||||
'public_notes',
|
||||
'status_id',
|
||||
'tax_name1',
|
||||
'tax_name2',
|
||||
'tax_name3',
|
||||
'tax_rate1',
|
||||
'tax_rate2',
|
||||
'tax_rate3',
|
||||
'terms',
|
||||
'total_taxes',
|
||||
// 'currency_id',
|
||||
'item.quantity',
|
||||
'item.cost',
|
||||
'item.product_key',
|
||||
'item.product_cost',
|
||||
'item.notes',
|
||||
'item.discount',
|
||||
'item.is_amount_discount',
|
||||
'item.tax_rate1',
|
||||
'item.tax_rate2',
|
||||
'item.tax_rate3',
|
||||
'item.tax_name1',
|
||||
'item.tax_name2',
|
||||
'item.tax_name3',
|
||||
'item.line_total',
|
||||
'item.gross_line_total',
|
||||
'item.custom_value1',
|
||||
'item.custom_value2',
|
||||
'item.custom_value3',
|
||||
'item.custom_value4',
|
||||
];
|
||||
|
||||
private array $decorate_keys = [
|
||||
'client',
|
||||
'currency',
|
||||
'currency_id',
|
||||
];
|
||||
|
||||
public function __construct(Company $company, array $input)
|
||||
@ -165,7 +110,7 @@ class InvoiceItemExport extends BaseExport
|
||||
$this->csv = Writer::createFromString();
|
||||
|
||||
if(count($this->input['report_keys']) == 0)
|
||||
$this->input['report_keys'] = ksort($this->all_keys);
|
||||
$this->input['report_keys'] = array_values($this->entity_keys);
|
||||
|
||||
//insert the header
|
||||
$this->csv->insertOne($this->buildHeader());
|
||||
@ -209,16 +154,20 @@ class InvoiceItemExport extends BaseExport
|
||||
|
||||
$entity = [];
|
||||
|
||||
$transformed_items = array_merge($transformed_invoice, $item_array);
|
||||
|
||||
$transformed_items = $this->decorateAdvancedFields($invoice, $transformed_items);
|
||||
|
||||
foreach(array_values($this->input['report_keys']) as $key)
|
||||
{
|
||||
$key = str_replace("item.", "", $key);
|
||||
$entity[$key] = $transformed_items[$key];
|
||||
$keyval = array_search($key, $this->entity_keys);
|
||||
|
||||
if(array_key_exists($key, $transformed_items))
|
||||
$entity[$keyval] = $transformed_items[$key];
|
||||
else
|
||||
$entity[$keyval] = "";
|
||||
|
||||
}
|
||||
|
||||
$transformed_items = array_merge($transformed_invoice, $item_array);
|
||||
$entity = $this->decorateAdvancedFields($invoice, $transformed_items);
|
||||
|
||||
$this->csv->insertOne($entity);
|
||||
|
||||
}
|
||||
@ -234,8 +183,12 @@ class InvoiceItemExport extends BaseExport
|
||||
|
||||
foreach(array_values($this->input['report_keys']) as $key){
|
||||
|
||||
if(!str_contains($key, "item."))
|
||||
$entity[$key] = $transformed_invoice[$key];
|
||||
$keyval = array_search($key, $this->entity_keys);
|
||||
|
||||
if(array_key_exists($key, $transformed_invoice))
|
||||
$entity[$keyval] = $transformed_invoice[$key];
|
||||
else
|
||||
$entity[$keyval] = "";
|
||||
|
||||
}
|
||||
|
||||
@ -245,14 +198,14 @@ class InvoiceItemExport extends BaseExport
|
||||
|
||||
private function decorateAdvancedFields(Invoice $invoice, array $entity) :array
|
||||
{
|
||||
if(array_key_exists('currency_id', $entity))
|
||||
$entity['currency_id'] = $invoice->client->currency()->code;
|
||||
if(in_array('currency_id', $this->input['report_keys']))
|
||||
$entity['currency'] = $invoice->client->currency() ? $invoice->client->currency()->code : $invoice->company->currency()->code;
|
||||
|
||||
if(array_key_exists('client_id', $entity))
|
||||
$entity['client_id'] = $invoice->client->present()->name();
|
||||
if(in_array('client_id', $this->input['report_keys']))
|
||||
$entity['client'] = $invoice->client->present()->name();
|
||||
|
||||
if(array_key_exists('status_id', $entity))
|
||||
$entity['status_id'] = $invoice->stringStatus($invoice->status_id);
|
||||
if(in_array('status_id', $this->input['report_keys']))
|
||||
$entity['status'] = $invoice->stringStatus($invoice->status_id);
|
||||
|
||||
return $entity;
|
||||
}
|
||||
|
@ -43,7 +43,7 @@ class PaymentExport extends BaseExport
|
||||
'custom_value4' => 'custom_value4',
|
||||
'date' => 'date',
|
||||
'exchange_currency' => 'exchange_currency_id',
|
||||
'gateway_type' => 'gateway_type_id',
|
||||
'gateway' => 'gateway_type_id',
|
||||
'number' => 'number',
|
||||
'private_notes' => 'private_notes',
|
||||
'project' => 'project_id',
|
||||
@ -54,28 +54,6 @@ class PaymentExport extends BaseExport
|
||||
'vendor' => 'vendor_id',
|
||||
];
|
||||
|
||||
protected array $all_keys = [
|
||||
'amount',
|
||||
'applied',
|
||||
'client_id',
|
||||
'currency_id',
|
||||
'custom_value1',
|
||||
'custom_value2',
|
||||
'custom_value3',
|
||||
'custom_value4',
|
||||
'date',
|
||||
'exchange_currency_id',
|
||||
'gateway_type_id',
|
||||
'number',
|
||||
'private_notes',
|
||||
'project_id',
|
||||
'refunded',
|
||||
'status_id',
|
||||
'transaction_reference',
|
||||
'type_id',
|
||||
'vendor_id',
|
||||
];
|
||||
|
||||
private array $decorate_keys = [
|
||||
'vendor',
|
||||
'status',
|
||||
@ -106,7 +84,7 @@ class PaymentExport extends BaseExport
|
||||
$this->csv = Writer::createFromString();
|
||||
|
||||
if(count($this->input['report_keys']) == 0)
|
||||
$this->input['report_keys'] = $this->all_keys;
|
||||
$this->input['report_keys'] = array_values($this->entity_keys);
|
||||
|
||||
//insert the header
|
||||
$this->csv->insertOne($this->buildHeader());
|
||||
@ -135,7 +113,12 @@ class PaymentExport extends BaseExport
|
||||
|
||||
foreach(array_values($this->input['report_keys']) as $key){
|
||||
|
||||
$entity[$key] = $transformed_entity[$key];
|
||||
$keyval = array_search($key, $this->entity_keys);
|
||||
|
||||
if(array_key_exists($key, $transformed_entity))
|
||||
$entity[$keyval] = $transformed_entity[$key];
|
||||
else
|
||||
$entity[$keyval] = '';
|
||||
|
||||
}
|
||||
|
||||
@ -146,26 +129,29 @@ class PaymentExport extends BaseExport
|
||||
private function decorateAdvancedFields(Payment $payment, array $entity) :array
|
||||
{
|
||||
|
||||
if(array_key_exists('status_id', $entity))
|
||||
$entity['status_id'] = $payment->stringStatus($payment->status_id);
|
||||
if(in_array('status_id', $this->input['report_keys']))
|
||||
$entity['status'] = $payment->stringStatus($payment->status_id);
|
||||
|
||||
if(array_key_exists('vendor_id', $entity))
|
||||
$entity['vendor_id'] = $payment->vendor()->exists() ? $payment->vendor->name : '';
|
||||
if(in_array('vendor_id', $this->input['report_keys']))
|
||||
$entity['vendor'] = $payment->vendor()->exists() ? $payment->vendor->name : '';
|
||||
|
||||
if(array_key_exists('project_id', $entity))
|
||||
$entity['project_id'] = $payment->project()->exists() ? $payment->project->name : '';
|
||||
if(in_array('project_id', $this->input['report_keys']))
|
||||
$entity['project'] = $payment->project()->exists() ? $payment->project->name : '';
|
||||
|
||||
if(array_key_exists('currency_id', $entity))
|
||||
$entity['currency_id'] = $payment->currency()->exists() ? $payment->currency->code : '';
|
||||
if(in_array('currency_id', $this->input['report_keys']))
|
||||
$entity['currency'] = $payment->currency()->exists() ? $payment->currency->code : '';
|
||||
|
||||
if(array_key_exists('exchange_currency_id', $entity))
|
||||
$entity['exchange_currency_id'] = $payment->exchange_currency()->exists() ? $payment->exchange_currency->code : '';
|
||||
if(in_array('exchange_currency_id', $this->input['report_keys']))
|
||||
$entity['exchange_currency'] = $payment->exchange_currency()->exists() ? $payment->exchange_currency->code : '';
|
||||
|
||||
if(array_key_exists('client_id', $entity))
|
||||
$entity['client_id'] = $payment->client->present()->name();
|
||||
if(in_array('client_id', $this->input['report_keys']))
|
||||
$entity['client'] = $payment->client->present()->name();
|
||||
|
||||
if(array_key_exists('type_id', $entity))
|
||||
$entity['type_id'] = $payment->translatedType();
|
||||
if(in_array('type_id', $this->input['report_keys']))
|
||||
$entity['type'] = $payment->translatedType();
|
||||
|
||||
if(in_array('gateway_type_id', $this->input['report_keys']))
|
||||
$entity['gateway'] = $payment->gateway_type ? $payment->gateway_type->name : "Unknown Type";
|
||||
|
||||
return $entity;
|
||||
}
|
||||
|
@ -52,26 +52,6 @@ class ProductExport extends BaseExport
|
||||
'tax_name3' => 'tax_name3',
|
||||
];
|
||||
|
||||
protected array $all_keys = [
|
||||
'project_id',
|
||||
'vendor_id',
|
||||
'custom_value1',
|
||||
'custom_value2',
|
||||
'custom_value3',
|
||||
'custom_value4',
|
||||
'product_key',
|
||||
'notes',
|
||||
'cost',
|
||||
'price',
|
||||
'quantity',
|
||||
'tax_rate1',
|
||||
'tax_rate2',
|
||||
'tax_rate3',
|
||||
'tax_name1',
|
||||
'tax_name2',
|
||||
'tax_name3',
|
||||
];
|
||||
|
||||
private array $decorate_keys = [
|
||||
'vendor',
|
||||
'project',
|
||||
@ -97,7 +77,7 @@ class ProductExport extends BaseExport
|
||||
$this->csv = Writer::createFromString();
|
||||
|
||||
if(count($this->input['report_keys']) == 0)
|
||||
$this->input['report_keys'] = $this->all_keys;
|
||||
$this->input['report_keys'] = array_values($this->entity_keys);
|
||||
|
||||
//insert the header
|
||||
$this->csv->insertOne($this->buildHeader());
|
||||
@ -126,7 +106,13 @@ class ProductExport extends BaseExport
|
||||
|
||||
foreach(array_values($this->input['report_keys']) as $key){
|
||||
|
||||
$entity[$key] = $transformed_entity[$key];
|
||||
$keyval = array_search($key, $this->entity_keys);
|
||||
|
||||
if(array_key_exists($key, $transformed_entity))
|
||||
$entity[$keyval] = $transformed_entity[$key];
|
||||
else
|
||||
$entity[$keyval] = '';
|
||||
|
||||
|
||||
}
|
||||
|
||||
@ -137,11 +123,11 @@ class ProductExport extends BaseExport
|
||||
private function decorateAdvancedFields(Product $product, array $entity) :array
|
||||
{
|
||||
|
||||
if(array_key_exists('vendor_id', $entity))
|
||||
$entity['vendor_id'] = $product->vendor()->exists() ? $product->vendor->name : '';
|
||||
if(in_array('vendor_id', $this->input['report_keys']))
|
||||
$entity['vendor'] = $product->vendor()->exists() ? $product->vendor->name : '';
|
||||
|
||||
if(array_key_exists('project_id', $entity))
|
||||
$entity['project_id'] = $product->project()->exists() ? $product->project->name : '';
|
||||
if(array_key_exists('project_id', $this->input['report_keys']))
|
||||
$entity['project'] = $product->project()->exists() ? $product->project->name : '';
|
||||
|
||||
return $entity;
|
||||
}
|
||||
|
@ -63,48 +63,10 @@ class QuoteExport extends BaseExport
|
||||
'tax_rate3' => 'tax_rate3',
|
||||
'terms' => 'terms',
|
||||
'total_taxes' => 'total_taxes',
|
||||
'currency' => 'client_id',
|
||||
'currency' => 'currency_id',
|
||||
'invoice' => 'invoice_id',
|
||||
];
|
||||
|
||||
protected array $all_keys = [
|
||||
'amount',
|
||||
'balance',
|
||||
'client_id',
|
||||
'custom_surcharge1',
|
||||
'custom_surcharge2',
|
||||
'custom_surcharge3',
|
||||
'custom_surcharge4',
|
||||
'custom_value1',
|
||||
'custom_value2',
|
||||
'custom_value3',
|
||||
'custom_value4',
|
||||
'date',
|
||||
'discount',
|
||||
'due_date',
|
||||
'exchange_rate',
|
||||
'footer',
|
||||
'number',
|
||||
'paid_to_date',
|
||||
'partial',
|
||||
'partial_due_date',
|
||||
'po_number',
|
||||
'private_notes',
|
||||
'public_notes',
|
||||
'status_id',
|
||||
'tax_name1',
|
||||
'tax_name2',
|
||||
'tax_name3',
|
||||
'tax_rate1',
|
||||
'tax_rate2',
|
||||
'tax_rate3',
|
||||
'terms',
|
||||
'total_taxes',
|
||||
'client_id',
|
||||
'invoice_id',
|
||||
];
|
||||
|
||||
|
||||
private array $decorate_keys = [
|
||||
'client',
|
||||
'currency',
|
||||
@ -131,13 +93,14 @@ class QuoteExport extends BaseExport
|
||||
$this->csv = Writer::createFromString();
|
||||
|
||||
if(count($this->input['report_keys']) == 0)
|
||||
$this->input['report_keys'] = $this->all_keys;
|
||||
$this->input['report_keys'] = array_values($this->entity_keys);
|
||||
|
||||
//insert the header
|
||||
$this->csv->insertOne($this->buildHeader());
|
||||
|
||||
$query = Quote::query()
|
||||
->with('client')->where('company_id', $this->company->id)
|
||||
->with('client')
|
||||
->where('company_id', $this->company->id)
|
||||
->where('is_deleted',0);
|
||||
|
||||
$query = $this->addDateRange($query);
|
||||
@ -163,7 +126,12 @@ class QuoteExport extends BaseExport
|
||||
|
||||
foreach(array_values($this->input['report_keys']) as $key){
|
||||
|
||||
$entity[$key] = $transformed_quote[$key];
|
||||
$keyval = array_search($key, $this->entity_keys);
|
||||
|
||||
if(array_key_exists($key, $transformed_quote))
|
||||
$entity[$keyval] = $transformed_quote[$key];
|
||||
else
|
||||
$entity[$keyval] = '';
|
||||
}
|
||||
|
||||
return $this->decorateAdvancedFields($quote, $entity);
|
||||
@ -172,13 +140,16 @@ class QuoteExport extends BaseExport
|
||||
|
||||
private function decorateAdvancedFields(Quote $quote, array $entity) :array
|
||||
{
|
||||
if(array_key_exists('currency', $entity))
|
||||
if(in_array('currency_id', $this->input['report_keys']))
|
||||
$entity['currency'] = $quote->client->currency()->code;
|
||||
|
||||
if(array_key_exists('client_id', $entity))
|
||||
$entity['client_id'] = $quote->client->present()->name();
|
||||
if(in_array('client_id', $this->input['report_keys']))
|
||||
$entity['client'] = $quote->client->present()->name();
|
||||
|
||||
if(array_key_exists('invoice', $entity))
|
||||
if(in_array('status_id',$this->input['report_keys']))
|
||||
$entity['status'] = $quote->stringStatus($quote->status_id);
|
||||
|
||||
if(in_array('invoice_id', $this->input['report_keys']))
|
||||
$entity['invoice'] = $quote->invoice ? $quote->invoice->number : "";
|
||||
|
||||
return $entity;
|
||||
|
@ -79,66 +79,12 @@ class QuoteItemExport extends BaseExport
|
||||
'tax_name3' => 'item.tax_name3',
|
||||
'line_total' => 'item.line_total',
|
||||
'gross_line_total' => 'item.gross_line_total',
|
||||
'invoice1' => 'item.custom_value1',
|
||||
'invoice2' => 'item.custom_value2',
|
||||
'invoice3' => 'item.custom_value3',
|
||||
'invoice4' => 'item.custom_value4',
|
||||
'custom_value1' => 'item.custom_value1',
|
||||
'custom_value2' => 'item.custom_value2',
|
||||
'custom_value3' => 'item.custom_value3',
|
||||
'custom_value4' => 'item.custom_value4',
|
||||
];
|
||||
|
||||
protected array $all_keys = [
|
||||
'amount',
|
||||
'balance',
|
||||
'client_id',
|
||||
'custom_surcharge1',
|
||||
'custom_surcharge2',
|
||||
'custom_surcharge3',
|
||||
'custom_surcharge4',
|
||||
'custom_value1',
|
||||
'custom_value2',
|
||||
'custom_value3',
|
||||
'custom_value4',
|
||||
'date',
|
||||
'discount',
|
||||
'due_date',
|
||||
'exchange_rate',
|
||||
'footer',
|
||||
'number',
|
||||
'paid_to_date',
|
||||
'partial',
|
||||
'partial_due_date',
|
||||
'po_number',
|
||||
'private_notes',
|
||||
'public_notes',
|
||||
'status_id',
|
||||
'tax_name1',
|
||||
'tax_name2',
|
||||
'tax_name3',
|
||||
'tax_rate1',
|
||||
'tax_rate2',
|
||||
'tax_rate3',
|
||||
'terms',
|
||||
'total_taxes',
|
||||
'currency_id',
|
||||
'item.quantity',
|
||||
'item.cost',
|
||||
'item.product_key',
|
||||
'item.product_cost',
|
||||
'item.notes',
|
||||
'item.discount',
|
||||
'item.is_amount_discount',
|
||||
'item.tax_rate1',
|
||||
'item.tax_rate2',
|
||||
'item.tax_rate3',
|
||||
'item.tax_name1',
|
||||
'item.tax_name2',
|
||||
'item.tax_name3',
|
||||
'item.line_total',
|
||||
'item.gross_line_total',
|
||||
'item.custom_value1',
|
||||
'item.custom_value2',
|
||||
'item.custom_value3',
|
||||
'item.custom_value4',
|
||||
];
|
||||
|
||||
private array $decorate_keys = [
|
||||
'client',
|
||||
@ -165,7 +111,8 @@ class QuoteItemExport extends BaseExport
|
||||
$this->csv = Writer::createFromString();
|
||||
|
||||
if(count($this->input['report_keys']) == 0)
|
||||
$this->input['report_keys'] = $this->all_keys;
|
||||
$this->input['report_keys'] = array_values($this->entity_keys);
|
||||
|
||||
|
||||
//insert the header
|
||||
$this->csv->insertOne($this->buildHeader());
|
||||
@ -209,16 +156,20 @@ class QuoteItemExport extends BaseExport
|
||||
|
||||
$entity = [];
|
||||
|
||||
$transformed_items = array_merge($transformed_quote, $item_array);
|
||||
|
||||
$transformed_items = $this->decorateAdvancedFields($quote, $transformed_items);
|
||||
|
||||
foreach(array_values($this->input['report_keys']) as $key)
|
||||
{
|
||||
$key = str_replace("item.", "", $key);
|
||||
$entity[$key] = $transformed_items[$key];
|
||||
$keyval = array_search($key, $this->entity_keys);
|
||||
|
||||
if(array_key_exists($key, $transformed_items))
|
||||
$entity[$keyval] = $transformed_items[$key];
|
||||
else
|
||||
$entity[$keyval] = "";
|
||||
}
|
||||
|
||||
|
||||
$transformed_items = array_merge($transformed_quote, $item_array);
|
||||
$entity = $this->decorateAdvancedFields($quote, $transformed_items);
|
||||
|
||||
$this->csv->insertOne($entity);
|
||||
|
||||
}
|
||||
@ -234,8 +185,12 @@ class QuoteItemExport extends BaseExport
|
||||
|
||||
foreach(array_values($this->input['report_keys']) as $key){
|
||||
|
||||
if(!str_contains($key, "item."))
|
||||
$entity[$key] = $transformed_quote[$key];
|
||||
$keyval = array_search($key, $this->entity_keys);
|
||||
|
||||
if(array_key_exists($key, $transformed_quote))
|
||||
$entity[$keyval] = $transformed_quote[$key];
|
||||
else
|
||||
$entity[$keyval] = "";
|
||||
|
||||
}
|
||||
|
||||
@ -245,14 +200,14 @@ class QuoteItemExport extends BaseExport
|
||||
|
||||
private function decorateAdvancedFields(Quote $quote, array $entity) :array
|
||||
{
|
||||
if(array_key_exists('currency_id', $entity))
|
||||
$entity['currency_id'] = $quote->client->currency()->code;
|
||||
if(in_array('currency_id', $this->input['report_keys']))
|
||||
$entity['currency'] = $quote->client->currency() ? $quote->client->currency()->code : $quote->company->currency()->code;
|
||||
|
||||
if(array_key_exists('client_id', $entity))
|
||||
$entity['client_id'] = $quote->client->present()->name();
|
||||
if(in_array('client_id', $this->input['report_keys']))
|
||||
$entity['client'] = $quote->client->present()->name();
|
||||
|
||||
if(array_key_exists('status_id', $entity))
|
||||
$entity['status_id'] = $quote->stringStatus($quote->status_id);
|
||||
if(in_array('status_id', $this->input['report_keys']))
|
||||
$entity['status'] = $quote->stringStatus($quote->status_id);
|
||||
|
||||
return $entity;
|
||||
}
|
||||
|
@ -63,49 +63,11 @@ class RecurringInvoiceExport extends BaseExport
|
||||
'tax_rate3' => 'tax_rate3',
|
||||
'terms' => 'terms',
|
||||
'total_taxes' => 'total_taxes',
|
||||
'currency' => 'client_id',
|
||||
'currency' => 'currency_id',
|
||||
'vendor' => 'vendor_id',
|
||||
'project' => 'project_id',
|
||||
];
|
||||
|
||||
protected array $all_keys = [
|
||||
'amount',
|
||||
'balance',
|
||||
'client_id',
|
||||
'custom_surcharge1',
|
||||
'custom_surcharge2',
|
||||
'custom_surcharge3',
|
||||
'custom_surcharge4',
|
||||
'custom_value1',
|
||||
'custom_value2',
|
||||
'custom_value3',
|
||||
'custom_value4',
|
||||
'date',
|
||||
'discount',
|
||||
'due_date',
|
||||
'exchange_rate',
|
||||
'footer',
|
||||
'number',
|
||||
'paid_to_date',
|
||||
'partial',
|
||||
'partial_due_date',
|
||||
'po_number',
|
||||
'private_notes',
|
||||
'public_notes',
|
||||
'status_id',
|
||||
'tax_name1',
|
||||
'tax_name2',
|
||||
'tax_name3',
|
||||
'tax_rate1',
|
||||
'tax_rate2',
|
||||
'tax_rate3',
|
||||
'terms',
|
||||
'total_taxes',
|
||||
'client_id',
|
||||
'vendor_id',
|
||||
'project_id',
|
||||
];
|
||||
|
||||
private array $decorate_keys = [
|
||||
'country',
|
||||
'client',
|
||||
@ -135,7 +97,7 @@ class RecurringInvoiceExport extends BaseExport
|
||||
$this->csv = Writer::createFromString();
|
||||
|
||||
if(count($this->input['report_keys']) == 0)
|
||||
$this->input['report_keys'] = $this->all_keys;
|
||||
$this->input['report_keys'] = array_values($this->entity_keys);
|
||||
|
||||
//insert the header
|
||||
$this->csv->insertOne($this->buildHeader());
|
||||
@ -167,7 +129,13 @@ class RecurringInvoiceExport extends BaseExport
|
||||
|
||||
foreach(array_values($this->input['report_keys']) as $key){
|
||||
|
||||
$entity[$key] = $transformed_invoice[$key];
|
||||
$keyval = array_search($key, $this->entity_keys);
|
||||
|
||||
if(array_key_exists($key, $transformed_invoice))
|
||||
$entity[$keyval] = $transformed_invoice[$key];
|
||||
else
|
||||
$entity[$keyval] = '';
|
||||
|
||||
}
|
||||
|
||||
return $this->decorateAdvancedFields($invoice, $entity);
|
||||
@ -176,20 +144,23 @@ class RecurringInvoiceExport extends BaseExport
|
||||
|
||||
private function decorateAdvancedFields(RecurringInvoice $invoice, array $entity) :array
|
||||
{
|
||||
if(array_key_exists('currency', $entity))
|
||||
$entity['currency'] = $invoice->client->currency()->code;
|
||||
if(in_array('country_id', $this->input['report_keys']))
|
||||
$entity['country'] = $invoice->client->country ? ctrans("texts.country_{$invoice->client->country->name}") : "";
|
||||
|
||||
if(array_key_exists('client_id', $entity))
|
||||
$entity['client_id'] = $invoice->client->present()->name();
|
||||
if(in_array('currency_id', $this->input['report_keys']))
|
||||
$entity['currency'] = $invoice->client->currency() ? $invoice->client->currency()->code : $invoice->company->currency()->code;
|
||||
|
||||
if(array_key_exists('status_id', $entity))
|
||||
$entity['status_id'] = $invoice->stringStatus($invoice->status_id);
|
||||
if(in_array('client_id', $this->input['report_keys']))
|
||||
$entity['client'] = $invoice->client->present()->name();
|
||||
|
||||
if(array_key_exists('vendor_id', $entity))
|
||||
$entity['vendor_id'] = $invoice->vendor()->exists() ? $invoice->vendor->name : '';
|
||||
if(in_array('status_id',$this->input['report_keys']))
|
||||
$entity['status'] = $invoice->stringStatus($invoice->status_id);
|
||||
|
||||
if(array_key_exists('project_id', $entity))
|
||||
$entity['project'] = $invoice->project()->exists() ? $invoice->project->name : '';
|
||||
if(in_array('project_id',$this->input['report_keys']))
|
||||
$entity['project'] = $invoice->project ? $invoice->project->name : "";
|
||||
|
||||
if(in_array('vendor_id',$this->input['report_keys']))
|
||||
$entity['vendor'] = $invoice->vendor ? $invoice->vendor->name : "";
|
||||
|
||||
return $entity;
|
||||
}
|
||||
|
@ -52,23 +52,6 @@ class TaskExport extends BaseExport
|
||||
'client' => 'client_id',
|
||||
];
|
||||
|
||||
protected array $all_keys = [
|
||||
'start_date',
|
||||
'end_date',
|
||||
'duration',
|
||||
'rate',
|
||||
'number',
|
||||
'description',
|
||||
'custom_value1',
|
||||
'custom_value2',
|
||||
'custom_value3',
|
||||
'custom_value4',
|
||||
'status_id',
|
||||
'project_id',
|
||||
'invoice_id',
|
||||
'client_id',
|
||||
];
|
||||
|
||||
private array $decorate_keys = [
|
||||
'status',
|
||||
'project',
|
||||
@ -99,10 +82,12 @@ class TaskExport extends BaseExport
|
||||
|
||||
//load the CSV document from a string
|
||||
$this->csv = Writer::createFromString();
|
||||
|
||||
|
||||
ksort($this->entity_keys);
|
||||
|
||||
if(count($this->input['report_keys']) == 0)
|
||||
$this->input['report_keys'] = $this->all_keys;
|
||||
$this->input['report_keys'] = array_values($this->entity_keys);
|
||||
|
||||
|
||||
//insert the header
|
||||
$this->csv->insertOne($this->buildHeader());
|
||||
@ -132,27 +117,35 @@ class TaskExport extends BaseExport
|
||||
|
||||
foreach(array_values($this->input['report_keys']) as $key){
|
||||
|
||||
$keyval = array_search($key, $this->entity_keys);
|
||||
|
||||
if(array_key_exists($key, $transformed_entity))
|
||||
$entity[$key] = $transformed_entity[$key];
|
||||
$entity[$keyval] = $transformed_entity[$key];
|
||||
else
|
||||
$entity[$key] = '';
|
||||
$entity[$keyval] = '';
|
||||
}
|
||||
|
||||
$entity['start_date'] = "";
|
||||
$entity['end_date'] = "";
|
||||
$entity['duration'] = "";
|
||||
|
||||
$entity = $this->decorateAdvancedFields($task, $entity);
|
||||
|
||||
ksort($entity);
|
||||
$this->csv->insertOne($entity);
|
||||
|
||||
}
|
||||
elseif(is_array(json_decode($task->time_log,1)) && count(json_decode($task->time_log,1)) > 0) {
|
||||
|
||||
foreach(array_values($this->input['report_keys']) as $key){
|
||||
|
||||
if(array_key_exists($key, $transformed_entity))
|
||||
$entity[$key] = $transformed_entity[$key];
|
||||
else
|
||||
$entity[$key] = '';
|
||||
}
|
||||
$keyval = array_search($key, $this->entity_keys);
|
||||
|
||||
$entity = $this->decorateAdvancedFields($task, $entity);
|
||||
if(array_key_exists($key, $transformed_entity))
|
||||
$entity[$keyval] = $transformed_entity[$key];
|
||||
else
|
||||
$entity[$keyval] = '';
|
||||
}
|
||||
|
||||
$this->iterateLogs($task, $entity);
|
||||
}
|
||||
@ -168,30 +161,45 @@ class TaskExport extends BaseExport
|
||||
$timezone_name = $timezone->name;
|
||||
|
||||
$logs = json_decode($task->time_log,1);
|
||||
|
||||
$date_format_default = "Y-m-d";
|
||||
|
||||
$date_format = DateFormat::find($task->company->settings->date_format_id);
|
||||
|
||||
if($date_format)
|
||||
$date_format_default = $date_format->format;
|
||||
|
||||
foreach($logs as $key => $item)
|
||||
{
|
||||
|
||||
if(in_array("start_date",$this->input['report_keys'])){
|
||||
$entity['start_date'] = Carbon::createFromTimeStamp($item[0])->setTimezone($timezone_name);
|
||||
nlog("start date" . $entity['start_date']);
|
||||
if(in_array("start_date", $this->input['report_keys'])){
|
||||
$entity['start_date'] = Carbon::createFromTimeStamp($item[0])->setTimezone($timezone_name)->format($date_format_default);
|
||||
}
|
||||
|
||||
if(in_array("end_date",$this->input['report_keys']) && $item[1] > 0){
|
||||
$entity['end_date'] = Carbon::createFromTimeStamp($item[1])->setTimezone($timezone_name);
|
||||
nlog("start date" . $entity['end_date']);
|
||||
if(in_array("end_date", $this->input['report_keys']) && $item[1] > 0){
|
||||
$entity['end_date'] = Carbon::createFromTimeStamp($item[1])->setTimezone($timezone_name)->format($date_format_default);
|
||||
}
|
||||
|
||||
if(in_array("end_date",$this->input['report_keys']) && $item[1] == 0){
|
||||
if(in_array("end_date", $this->input['report_keys']) && $item[1] == 0){
|
||||
$entity['end_date'] = ctrans('texts.is_running');
|
||||
nlog("start date" . $entity['end_date']);
|
||||
}
|
||||
|
||||
if(in_array("duration",$this->input['report_keys'])){
|
||||
if(in_array("duration", $this->input['report_keys'])){
|
||||
$entity['duration'] = $task->calcDuration();
|
||||
nlog("duration" . $entity['duration']);
|
||||
}
|
||||
|
||||
if(!array_key_exists('duration', $entity))
|
||||
$entity['duration'] = "";
|
||||
|
||||
if(!array_key_exists('start_date', $entity))
|
||||
$entity['start_date'] = "";
|
||||
|
||||
if(!array_key_exists('end_date', $entity))
|
||||
$entity['end_date'] = "";
|
||||
|
||||
$entity = $this->decorateAdvancedFields($task, $entity);
|
||||
|
||||
ksort($entity);
|
||||
$this->csv->insertOne($entity);
|
||||
|
||||
unset($entity['start_date']);
|
||||
@ -204,16 +212,17 @@ class TaskExport extends BaseExport
|
||||
private function decorateAdvancedFields(Task $task, array $entity) :array
|
||||
{
|
||||
|
||||
if(array_key_exists('status_id', $entity))
|
||||
$entity['status_id'] = $task->status()->exists() ? $task->status->name : '';
|
||||
if(in_array('status_id', $this->input['report_keys']))
|
||||
$entity['status'] = $task->status()->exists() ? $task->status->name : '';
|
||||
|
||||
if(array_key_exists('project_id', $entity))
|
||||
$entity['project_id'] = $task->project()->exists() ? $task->project->name : '';
|
||||
|
||||
if(array_key_exists('client_id', $entity))
|
||||
$entity['client_id'] = $task->client->present()->name();
|
||||
if(in_array('project_id', $this->input['report_keys']))
|
||||
$entity['project'] = $task->project()->exists() ? $task->project->name : '';
|
||||
|
||||
if(in_array('client_id', $this->input['report_keys']))
|
||||
$entity['client'] = $task->client ? $task->client->present()->name() : "";
|
||||
|
||||
if(in_array('invoice_id', $this->input['report_keys']))
|
||||
$entity['invoice'] = $task->invoice ? $task->invoice->number : "";
|
||||
|
||||
return $entity;
|
||||
}
|
||||
|
@ -39,6 +39,9 @@ class ExpenseFactory
|
||||
$expense->custom_value2 = '';
|
||||
$expense->custom_value3 = '';
|
||||
$expense->custom_value4 = '';
|
||||
$expense->tax_amount1 = 0;
|
||||
$expense->tax_amount2 = 0;
|
||||
$expense->tax_amount3 = 0;
|
||||
|
||||
return $expense;
|
||||
}
|
||||
|
@ -33,6 +33,7 @@ class PaymentFactory
|
||||
$payment->transaction_reference = null;
|
||||
$payment->payer_id = null;
|
||||
$payment->status_id = Payment::STATUS_PENDING;
|
||||
$payment->exchange_rate = 1;
|
||||
|
||||
return $payment;
|
||||
}
|
||||
|
@ -30,6 +30,11 @@ class PaymentMethodController extends Controller
|
||||
{
|
||||
use MakesDates;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->middleware('throttle:10,1')->only('store');
|
||||
}
|
||||
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*
|
||||
@ -92,7 +97,6 @@ class PaymentMethodController extends Controller
|
||||
|
||||
public function verify(ClientGatewayToken $payment_method)
|
||||
{
|
||||
// $gateway = $this->getClientGateway();
|
||||
|
||||
return $payment_method->gateway
|
||||
->driver(auth()->user()->client)
|
||||
|
87
app/Http/Controllers/Reports/ProfitAndLossController.php
Normal file
87
app/Http/Controllers/Reports/ProfitAndLossController.php
Normal file
@ -0,0 +1,87 @@
|
||||
<?php
|
||||
/**
|
||||
* Invoice Ninja (https://invoiceninja.com).
|
||||
*
|
||||
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||
*
|
||||
* @copyright Copyright (c) 2022. Invoice Ninja LLC (https://invoiceninja.com)
|
||||
*
|
||||
* @license https://www.elastic.co/licensing/elastic-license
|
||||
*/
|
||||
|
||||
namespace App\Http\Controllers\Reports;
|
||||
|
||||
use App\Export\CSV\PaymentExport;
|
||||
use App\Http\Controllers\BaseController;
|
||||
use App\Http\Requests\Report\ProfitLossRequest;
|
||||
use App\Models\Client;
|
||||
use App\Services\Report\ProfitLoss;
|
||||
use App\Utils\Traits\MakesHash;
|
||||
use Illuminate\Http\Response;
|
||||
|
||||
class ProfitAndLossController extends BaseController
|
||||
{
|
||||
use MakesHash;
|
||||
|
||||
private string $filename = 'profit_and_loss.csv';
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
/**
|
||||
* @OA\Post(
|
||||
* path="/api/v1/reports/profitloss",
|
||||
* operationId="getProfitLossReport",
|
||||
* tags={"reports"},
|
||||
* summary="Profit loss reports",
|
||||
* description="Profit loss report",
|
||||
* @OA\Parameter(ref="#/components/parameters/X-Api-Secret"),
|
||||
* @OA\Parameter(ref="#/components/parameters/X-Requested-With"),
|
||||
* @OA\RequestBody(
|
||||
* required=true,
|
||||
* @OA\JsonContent(ref="#/components/schemas/GenericReportSchema")
|
||||
* ),
|
||||
* @OA\Response(
|
||||
* response=200,
|
||||
* description="success",
|
||||
* @OA\Header(header="X-MINIMUM-CLIENT-VERSION", ref="#/components/headers/X-MINIMUM-CLIENT-VERSION"),
|
||||
* @OA\Header(header="X-RateLimit-Remaining", ref="#/components/headers/X-RateLimit-Remaining"),
|
||||
* @OA\Header(header="X-RateLimit-Limit", ref="#/components/headers/X-RateLimit-Limit"),
|
||||
* ),
|
||||
* @OA\Response(
|
||||
* response=422,
|
||||
* description="Validation error",
|
||||
* @OA\JsonContent(ref="#/components/schemas/ValidationError"),
|
||||
* ),
|
||||
* @OA\Response(
|
||||
* response="default",
|
||||
* description="Unexpected Error",
|
||||
* @OA\JsonContent(ref="#/components/schemas/Error"),
|
||||
* ),
|
||||
* )
|
||||
*/
|
||||
public function __invoke(ProfitLossRequest $request)
|
||||
{
|
||||
// expect a list of visible fields, or use the default
|
||||
|
||||
$pnl = new ProfitLoss(auth()->user()->company(), $request->all());
|
||||
$pnl->build();
|
||||
|
||||
$csv = $pnl->getCsv();
|
||||
|
||||
$headers = array(
|
||||
'Content-Disposition' => 'attachment',
|
||||
'Content-Type' => 'text/csv',
|
||||
);
|
||||
|
||||
return response()->streamDownload(function () use ($csv) {
|
||||
echo $csv;
|
||||
}, $this->filename, $headers);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
@ -32,7 +32,7 @@ class GenericReportRequest extends Request
|
||||
'end_date' => 'string|date',
|
||||
'date_key' => 'string',
|
||||
'date_range' => 'string',
|
||||
'report_keys' => 'sometimes|array'
|
||||
'report_keys' => 'present|array'
|
||||
];
|
||||
}
|
||||
}
|
||||
|
39
app/Http/Requests/Report/ProfitLossRequest.php
Normal file
39
app/Http/Requests/Report/ProfitLossRequest.php
Normal file
@ -0,0 +1,39 @@
|
||||
<?php
|
||||
/**
|
||||
* Invoice Ninja (https://invoiceninja.com).
|
||||
*
|
||||
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||
*
|
||||
* @copyright Copyright (c) 2022. Invoice Ninja LLC (https://invoiceninja.com)
|
||||
*
|
||||
* @license https://www.elastic.co/licensing/elastic-license
|
||||
*/
|
||||
|
||||
namespace App\Http\Requests\Report;
|
||||
|
||||
use App\Http\Requests\Request;
|
||||
|
||||
class ProfitLossRequest extends Request
|
||||
{
|
||||
/**
|
||||
* Determine if the user is authorized to make this request.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function authorize() : bool
|
||||
{
|
||||
return auth()->user()->isAdmin();
|
||||
}
|
||||
|
||||
public function rules()
|
||||
{
|
||||
return [
|
||||
'start_date' => 'string|date',
|
||||
'end_date' => 'string|date',
|
||||
'is_income_billed' => 'required|bail|bool',
|
||||
'is_expense_billed' => 'required|bail|bool',
|
||||
'include_tax' => 'required|bail|bool',
|
||||
'date_range' => 'required|bail|string'
|
||||
];
|
||||
}
|
||||
}
|
@ -21,6 +21,8 @@ class BlackListRule implements Rule
|
||||
{
|
||||
private array $blacklist = [
|
||||
'candassociates.com',
|
||||
'vusra.com',
|
||||
'fourthgenet.com',
|
||||
];
|
||||
|
||||
/**
|
||||
|
@ -277,11 +277,13 @@ class CompanyImport implements ShouldQueue
|
||||
'errors' => []
|
||||
];
|
||||
|
||||
$_company = Company::find($this->company->id);
|
||||
|
||||
$nmo = new NinjaMailerObject;
|
||||
$nmo->mailable = new ImportCompleted($this->company, $data);
|
||||
$nmo->company = $this->company;
|
||||
$nmo->settings = $this->company->settings;
|
||||
$nmo->to_user = $this->company->owner();
|
||||
$nmo->mailable = new ImportCompleted($_company, $data);
|
||||
$nmo->company = $_company;
|
||||
$nmo->settings = $_company->settings;
|
||||
$nmo->to_user = $_company->owner();
|
||||
NinjaMailerJob::dispatchNow($nmo);
|
||||
|
||||
}
|
||||
@ -1450,6 +1452,20 @@ class CompanyImport implements ShouldQueue
|
||||
$new_obj->save(['timestamps' => false]);
|
||||
$new_obj->number = $this->getNextRecurringExpenseNumber($new_obj);
|
||||
}
|
||||
elseif($class == 'App\Models\Project' && is_null($obj->{$match_key})){
|
||||
$new_obj = new Project();
|
||||
$new_obj->company_id = $this->company->id;
|
||||
$new_obj->fill($obj_array);
|
||||
$new_obj->save(['timestamps' => false]);
|
||||
$new_obj->number = $this->getNextProjectNumber($new_obj);
|
||||
}
|
||||
elseif($class == 'App\Models\Task' && is_null($obj->{$match_key})){
|
||||
$new_obj = new Task();
|
||||
$new_obj->company_id = $this->company->id;
|
||||
$new_obj->fill($obj_array);
|
||||
$new_obj->save(['timestamps' => false]);
|
||||
$new_obj->number = $this->getNextTaskNumber($new_obj);
|
||||
}
|
||||
elseif($class == 'App\Models\CompanyLedger'){
|
||||
$new_obj = $class::firstOrNew(
|
||||
[$match_key => $obj->{$match_key}, 'company_id' => $this->company->id],
|
||||
@ -1514,10 +1530,9 @@ class CompanyImport implements ShouldQueue
|
||||
}
|
||||
|
||||
if (! array_key_exists($resource, $this->ids)) {
|
||||
nlog($resource);
|
||||
|
||||
$this->sendImportMail("The Import failed due to missing data in the import file. Resource {$resource} not available.");
|
||||
nlog($this->ids);
|
||||
|
||||
throw new \Exception("Resource {$resource} not available.");
|
||||
}
|
||||
|
||||
@ -1547,8 +1562,10 @@ class CompanyImport implements ShouldQueue
|
||||
$t = app('translator');
|
||||
$t->replace(Ninja::transformTranslations($this->company->settings));
|
||||
|
||||
$_company = Company::find($this->company->id);
|
||||
|
||||
$nmo = new NinjaMailerObject;
|
||||
$nmo->mailable = new CompanyImportFailure($this->company, $message);
|
||||
$nmo->mailable = new CompanyImportFailure($_company, $message);
|
||||
$nmo->company = $this->company;
|
||||
$nmo->settings = $this->company->settings;
|
||||
$nmo->to_user = $this->company->owner();
|
||||
|
@ -131,7 +131,7 @@ class NinjaMailerJob implements ShouldQueue
|
||||
$response = $e->getResponse();
|
||||
$message_body = json_decode($response->getBody()->getContents());
|
||||
|
||||
if(property_exists($message_body, 'Message')){
|
||||
if($message_body && property_exists($message_body, 'Message')){
|
||||
$message = $message_body->Message;
|
||||
nlog($message);
|
||||
}
|
||||
@ -268,9 +268,10 @@ class NinjaMailerJob implements ShouldQueue
|
||||
return false;
|
||||
|
||||
/* On the hosted platform, if the user is over the email quotas, we do not send the email. */
|
||||
if(Ninja::isHosted() && $this->company->account->emailQuotaExceeded())
|
||||
if(Ninja::isHosted() && $this->company->account && $this->company->account->emailQuotaExceeded())
|
||||
return true;
|
||||
|
||||
/* Ensure the user has a valid email address */
|
||||
if(!str_contains($this->nmo->to_user->email, "@"))
|
||||
return true;
|
||||
|
||||
|
89
app/Jobs/Report/ProfitAndLoss.php
Normal file
89
app/Jobs/Report/ProfitAndLoss.php
Normal file
@ -0,0 +1,89 @@
|
||||
<?php
|
||||
/**
|
||||
* Invoice Ninja (https://invoiceninja.com).
|
||||
*
|
||||
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||
*
|
||||
* @copyright Copyright (c) 2022. Invoice Ninja LLC (https://invoiceninja.com)
|
||||
*
|
||||
* @license https://www.elastic.co/licensing/elastic-license
|
||||
*/
|
||||
|
||||
namespace App\Jobs\Report;
|
||||
|
||||
use App\Libraries\MultiDB;
|
||||
use App\Models\Company;
|
||||
use App\Services\Report\ProfitLoss;
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Foundation\Bus\Dispatchable;
|
||||
use Illuminate\Queue\InteractsWithQueue;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
|
||||
class ProfitAndLoss implements ShouldQueue
|
||||
{
|
||||
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
|
||||
|
||||
protected Company $company;
|
||||
|
||||
protected array $payload;
|
||||
|
||||
/**
|
||||
* Create a new job instance.
|
||||
*
|
||||
* @param RecurringInvoice $recurring_invoice
|
||||
* @param string $db
|
||||
*/
|
||||
public function __construct(Company $company, array $payload)
|
||||
{
|
||||
$this->company = $company;
|
||||
|
||||
$this->payload = $payload;
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the job.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function handle() : void
|
||||
{
|
||||
|
||||
MultiDB::setDb($this->company->db);
|
||||
|
||||
/*
|
||||
payload variables.
|
||||
|
||||
start_date - Y-m-d
|
||||
end_date - Y-m-d
|
||||
date_range -
|
||||
all
|
||||
last7
|
||||
last30
|
||||
this_month
|
||||
last_month
|
||||
this_quarter
|
||||
last_quarter
|
||||
this_year
|
||||
custom
|
||||
income_billed - true = Invoiced || false = Payments
|
||||
expense_billed - true = Expensed || false = Expenses marked as paid
|
||||
include_tax - true tax_included || false - tax_excluded
|
||||
|
||||
*/
|
||||
|
||||
$pl = new ProfitLoss($this->company, $this->payload);
|
||||
|
||||
$pl->build();
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
public function failed($exception = null)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
@ -50,10 +50,6 @@ class CompanyDeleted extends Mailable
|
||||
public function build()
|
||||
{
|
||||
App::forgetInstance('translator');
|
||||
|
||||
if($this->company)
|
||||
App::setLocale($this->company->getLocale());
|
||||
|
||||
$t = app('translator');
|
||||
$t->replace(Ninja::transformTranslations($this->settings));
|
||||
|
||||
|
@ -14,14 +14,19 @@ namespace App\Mail\Engine;
|
||||
use App\DataMapper\EmailTemplateDefaults;
|
||||
use App\Jobs\Entity\CreateEntityPdf;
|
||||
use App\Models\Account;
|
||||
use App\Models\Expense;
|
||||
use App\Models\Task;
|
||||
use App\Utils\HtmlEngine;
|
||||
use App\Utils\Ninja;
|
||||
use App\Utils\Number;
|
||||
use App\Utils\Traits\MakesHash;
|
||||
use Illuminate\Support\Facades\App;
|
||||
use Illuminate\Support\Facades\Lang;
|
||||
|
||||
class InvoiceEmailEngine extends BaseEmailEngine
|
||||
{
|
||||
use MakesHash;
|
||||
|
||||
public $invitation;
|
||||
|
||||
public $client;
|
||||
@ -146,6 +151,53 @@ class InvoiceEmailEngine extends BaseEmailEngine
|
||||
$this->setAttachments([['path' => $document->filePath(), 'name' => $document->name, 'mime' => $document->type]]);
|
||||
}
|
||||
|
||||
$line_items = $this->invoice->line_items;
|
||||
|
||||
$expense_ids = [];
|
||||
|
||||
foreach($line_items as $item)
|
||||
{
|
||||
if(property_exists($item, 'expense_id'))
|
||||
{
|
||||
$expense_ids[] = $item->expense_id;
|
||||
}
|
||||
|
||||
if(count($expense_ids) > 0){
|
||||
|
||||
$expenses = Expense::whereIn('id', $this->transformKeys($expense_ids))
|
||||
->where('invoice_documents', 1)
|
||||
->cursor()
|
||||
->each(function ($expense){
|
||||
|
||||
foreach($expense->documents as $document)
|
||||
{
|
||||
$this->setAttachments([['path' => $document->filePath(), 'name' => $document->name, 'mime' => $document->type]]);
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
if(property_exists($item, 'task_id'))
|
||||
{
|
||||
$task_ids[] = $item->task_id;
|
||||
}
|
||||
|
||||
if(count($task_ids) > 0 && $this->invoice->company->invoice_task_documents){
|
||||
|
||||
$tasks = Task::whereIn('id', $this->transformKeys($task_ids))
|
||||
->cursor()
|
||||
->each(function ($task){
|
||||
|
||||
foreach($task->documents as $document)
|
||||
{
|
||||
$this->setAttachments([['path' => $document->filePath(), 'name' => $document->name, 'mime' => $document->type]]);
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
@ -58,6 +58,22 @@ class ImportCompleted extends Mailable
|
||||
'logo' => $this->company->present()->logo(),
|
||||
'settings' => $this->company->settings,
|
||||
'company' => $this->company,
|
||||
'client_count' => $this->company->clients()->count(),
|
||||
'product_count' => $this->company->products()->count(),
|
||||
'invoice_count' => $this->company->invoices()->count(),
|
||||
'quote_count' => $this->company->quotes()->count(),
|
||||
'credit_count' => $this->company->credits()->count(),
|
||||
'project_count' => $this->company->projects()->count(),
|
||||
'task_count' => $this->company->tasks()->count(),
|
||||
'vendor_count' => $this->company->vendors()->count(),
|
||||
'payment_count' => $this->company->payments()->count(),
|
||||
'recurring_invoice_count' => $this->company->recurring_invoices()->count(),
|
||||
'expense_count' => $this->company->expenses()->count(),
|
||||
'company_gateway_count' => $this->company->company_gateways()->count(),
|
||||
'client_gateway_token_count' => $this->company->client_gateway_tokens()->count(),
|
||||
'tax_rate_count' => $this->company->tax_rates()->count(),
|
||||
'document_count' => $this->company->documents()->count(),
|
||||
|
||||
]);
|
||||
|
||||
return $this
|
||||
|
@ -253,7 +253,7 @@ class Client extends BaseModel implements HasLocalePreference
|
||||
|
||||
public function system_logs()
|
||||
{
|
||||
return $this->hasMany(SystemLog::class)->orderBy('id', 'desc');
|
||||
return $this->hasMany(SystemLog::class)->take(50)->orderBy('id', 'desc');
|
||||
}
|
||||
|
||||
public function timezone()
|
||||
|
@ -118,9 +118,7 @@ class Company extends BaseModel
|
||||
'client_registration_fields' => 'array',
|
||||
];
|
||||
|
||||
protected $with = [
|
||||
// 'tokens'
|
||||
];
|
||||
protected $with = [];
|
||||
|
||||
public static $modules = [
|
||||
self::ENTITY_RECURRING_INVOICE => 1,
|
||||
@ -553,4 +551,17 @@ class Company extends BaseModel
|
||||
{
|
||||
return ctrans('texts.company');
|
||||
}
|
||||
|
||||
public function date_format()
|
||||
{
|
||||
$date_formats = Cache::get('date_formats');
|
||||
|
||||
if(!$date_formats)
|
||||
$this->buildCache(true);
|
||||
|
||||
return $date_formats->filter(function ($item) {
|
||||
return $item->id == $this->getSetting('date_format_id');
|
||||
})->first()->format;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -319,4 +319,25 @@ class Credit extends BaseModel
|
||||
{
|
||||
return ctrans('texts.credit');
|
||||
}
|
||||
|
||||
public static function stringStatus(int $status)
|
||||
{
|
||||
switch ($status) {
|
||||
case self::STATUS_DRAFT:
|
||||
return ctrans('texts.draft');
|
||||
break;
|
||||
case self::STATUS_SENT:
|
||||
return ctrans('texts.sent');
|
||||
break;
|
||||
case self::STATUS_PARTIAL:
|
||||
return ctrans('texts.partial');
|
||||
break;
|
||||
case self::STATUS_APPLIED:
|
||||
return ctrans('texts.applied');
|
||||
break;
|
||||
default:
|
||||
return "";
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -114,7 +114,7 @@ class Expense extends BaseModel
|
||||
|
||||
public function category()
|
||||
{
|
||||
return $this->belongsTo(ExpenseCategory::class);
|
||||
return $this->belongsTo(ExpenseCategory::class)->withTrashed();
|
||||
}
|
||||
|
||||
public function payment_type()
|
||||
|
@ -55,6 +55,11 @@ class Product extends BaseModel
|
||||
return $this->belongsTo(User::class)->withTrashed();
|
||||
}
|
||||
|
||||
public function vendor()
|
||||
{
|
||||
return $this->belongsTo(Vendor::class)->withTrashed();
|
||||
}
|
||||
|
||||
public function assigned_user()
|
||||
{
|
||||
return $this->belongsTo(User::class, 'assigned_user_id', 'id')->withTrashed();
|
||||
|
@ -72,11 +72,15 @@ class WePayFailureNotification extends Notification
|
||||
|
||||
public function toSlack($notifiable)
|
||||
{
|
||||
$ip = "";
|
||||
|
||||
if(request())
|
||||
$ip = request()->getClientIp();
|
||||
|
||||
(new SlackMessage)
|
||||
return (new SlackMessage)
|
||||
->success()
|
||||
->from(ctrans('texts.notification_bot'))
|
||||
->image('https://app.invoiceninja.com/favicon.png')
|
||||
->content("New WePay ACH Failure from Company ID: ". $this->company_id);
|
||||
->content("New WePay ACH Failure from Company ID: {$this->company_id} IP: {$ip}" );
|
||||
}
|
||||
}
|
||||
|
@ -230,14 +230,11 @@ class GoCardlessPaymentDriver extends BaseDriver
|
||||
public function processWebhookRequest(PaymentWebhookRequest $request)
|
||||
{
|
||||
// Allow app to catch up with webhook request.
|
||||
sleep(2);
|
||||
|
||||
$this->init();
|
||||
|
||||
nlog("GoCardless Event");
|
||||
nlog($request->all());
|
||||
|
||||
|
||||
if(!is_array($request->events) || !is_object($request->events)){
|
||||
|
||||
nlog("No GoCardless events to process in response?");
|
||||
@ -245,19 +242,24 @@ class GoCardlessPaymentDriver extends BaseDriver
|
||||
|
||||
}
|
||||
|
||||
sleep(1);
|
||||
|
||||
foreach ($request->events as $event) {
|
||||
if ($event['action'] === 'confirmed') {
|
||||
|
||||
nlog("Searching for transaction reference");
|
||||
|
||||
$payment = Payment::query()
|
||||
->where('transaction_reference', $event['links']['payment'])
|
||||
->where('company_id', $request->getCompany()->id)
|
||||
// ->where('company_id', $request->getCompany()->id)
|
||||
->first();
|
||||
|
||||
if ($payment) {
|
||||
$payment->status_id = Payment::STATUS_COMPLETED;
|
||||
$payment->save();
|
||||
}
|
||||
|
||||
|
||||
else
|
||||
nlog("I was unable to find the payment for this reference");
|
||||
//finalize payments on invoices here.
|
||||
|
||||
}
|
||||
@ -266,7 +268,7 @@ class GoCardlessPaymentDriver extends BaseDriver
|
||||
|
||||
$payment = Payment::query()
|
||||
->where('transaction_reference', $event['links']['payment'])
|
||||
->where('company_id', $request->getCompany()->id)
|
||||
// ->where('company_id', $request->getCompany()->id)
|
||||
->first();
|
||||
|
||||
if ($payment) {
|
||||
|
@ -601,9 +601,14 @@ class StripePaymentDriver extends BaseDriver
|
||||
}
|
||||
|
||||
} elseif ($request->type === 'source.chargeable') {
|
||||
|
||||
$this->init();
|
||||
|
||||
foreach ($request->data as $transaction) {
|
||||
|
||||
if(!$request->data['object']['amount'] || empty($request->data['object']['amount']))
|
||||
continue;
|
||||
|
||||
$charge = \Stripe\Charge::create([
|
||||
'amount' => $request->data['object']['amount'],
|
||||
'currency' => $request->data['object']['currency'],
|
||||
@ -619,6 +624,7 @@ class StripePaymentDriver extends BaseDriver
|
||||
->orWhere('transaction_reference', $transaction['id']);
|
||||
})
|
||||
->first();
|
||||
|
||||
if ($payment) {
|
||||
$payment->status_id = Payment::STATUS_COMPLETED;
|
||||
$payment->save();
|
||||
|
@ -12,8 +12,10 @@
|
||||
namespace App\Repositories;
|
||||
|
||||
use App\Factory\ExpenseFactory;
|
||||
use App\Libraries\Currency\Conversion\CurrencyApi;
|
||||
use App\Models\Expense;
|
||||
use App\Utils\Traits\GeneratesCounter;
|
||||
use Illuminate\Support\Carbon;
|
||||
|
||||
/**
|
||||
* ExpenseRepository.
|
||||
@ -34,6 +36,10 @@ class ExpenseRepository extends BaseRepository
|
||||
public function save(array $data, Expense $expense) : ?Expense
|
||||
{
|
||||
$expense->fill($data);
|
||||
|
||||
if(!$expense->id)
|
||||
$expense = $this->processExchangeRates($data, $expense);
|
||||
|
||||
$expense->number = empty($expense->number) ? $this->getNextExpenseNumber($expense) : $expense->number;
|
||||
$expense->save();
|
||||
|
||||
@ -57,4 +63,27 @@ class ExpenseRepository extends BaseRepository
|
||||
ExpenseFactory::create(auth()->user()->company()->id, auth()->user()->id)
|
||||
);
|
||||
}
|
||||
|
||||
public function processExchangeRates($data, $expense)
|
||||
{
|
||||
|
||||
if(array_key_exists('exchange_rate', $data) && isset($data['exchange_rate']) && $data['exchange_rate'] != 1){
|
||||
return $expense;
|
||||
}
|
||||
|
||||
$expense_currency = $data['currency_id'];
|
||||
$company_currency = $expense->company->settings->currency_id;
|
||||
|
||||
if ($company_currency != $expense_currency) {
|
||||
|
||||
$exchange_rate = new CurrencyApi();
|
||||
|
||||
$expense->exchange_rate = $exchange_rate->exchangeRate($expense_currency, $company_currency, Carbon::parse($expense->date));
|
||||
|
||||
return $expense;
|
||||
}
|
||||
|
||||
return $expense;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -66,7 +66,11 @@ class PaymentRepository extends BaseRepository {
|
||||
|
||||
//check currencies here and fill the exchange rate data if necessary
|
||||
if (! $payment->id) {
|
||||
$this->processExchangeRates($data, $payment);
|
||||
$payment = $this->processExchangeRates($data, $payment);
|
||||
|
||||
/* This is needed here otherwise the ->fill() overwrites anything that exists*/
|
||||
if($payment->exchange_rate != 1)
|
||||
unset($data['exchange_rate']);
|
||||
|
||||
$is_existing_payment = false;
|
||||
$client = Client::where('id', $data['client_id'])->withTrashed()->first();
|
||||
@ -100,7 +104,12 @@ class PaymentRepository extends BaseRepository {
|
||||
$payment->status_id = Payment::STATUS_COMPLETED;
|
||||
|
||||
if (! $payment->currency_id && $client) {
|
||||
$payment->currency_id = $client->company->settings->currency_id;
|
||||
|
||||
if(property_exists($client->settings, 'currency_id'))
|
||||
$payment->currency_id = $client->settings->currency_id;
|
||||
else
|
||||
$payment->currency_id = $client->company->settings->currency_id;
|
||||
|
||||
}
|
||||
|
||||
$payment->save();
|
||||
@ -199,8 +208,9 @@ class PaymentRepository extends BaseRepository {
|
||||
public function processExchangeRates($data, $payment)
|
||||
{
|
||||
|
||||
if(array_key_exists('exchange_rate', $data) && isset($data['exchange_rate']))
|
||||
if(array_key_exists('exchange_rate', $data) && isset($data['exchange_rate']) && $data['exchange_rate'] != 1){
|
||||
return $payment;
|
||||
}
|
||||
|
||||
$client = Client::withTrashed()->find($data['client_id']);
|
||||
|
||||
@ -212,7 +222,6 @@ class PaymentRepository extends BaseRepository {
|
||||
$exchange_rate = new CurrencyApi();
|
||||
|
||||
$payment->exchange_rate = $exchange_rate->exchangeRate($client_currency, $company_currency, Carbon::parse($payment->date));
|
||||
// $payment->exchange_currency_id = $client_currency;
|
||||
$payment->exchange_currency_id = $company_currency;
|
||||
$payment->currency_id = $client_currency;
|
||||
|
||||
@ -221,7 +230,6 @@ class PaymentRepository extends BaseRepository {
|
||||
|
||||
$payment->currency_id = $company_currency;
|
||||
|
||||
|
||||
return $payment;
|
||||
}
|
||||
|
||||
|
@ -226,6 +226,7 @@ class Statement
|
||||
->whereIn('status_id', $this->invoiceStatuses())
|
||||
->whereBetween('date', [Carbon::parse($this->options['start_date']), Carbon::parse($this->options['end_date'])])
|
||||
->orderBy('due_date', 'ASC')
|
||||
->orderBy('date', 'ASC')
|
||||
->cursor();
|
||||
}
|
||||
|
||||
@ -241,10 +242,10 @@ class Statement
|
||||
return [Invoice::STATUS_SENT, Invoice::STATUS_PARTIAL, Invoice::STATUS_PAID];
|
||||
break;
|
||||
case 'paid':
|
||||
return [Invoice::STATUS_PARTIAL, Invoice::STATUS_PAID];
|
||||
return [Invoice::STATUS_PAID];
|
||||
break;
|
||||
case 'unpaid':
|
||||
return [Invoice::STATUS_SENT];
|
||||
return [Invoice::STATUS_SENT, Invoice::STATUS_PARTIAL];
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -61,7 +61,7 @@ class MarkPaid extends AbstractService
|
||||
$payment->transaction_reference = ctrans('texts.manual_entry');
|
||||
$payment->currency_id = $this->invoice->client->getSetting('currency_id');
|
||||
$payment->is_manual = true;
|
||||
|
||||
|
||||
if($this->invoice->company->timezone())
|
||||
$payment->date = now()->addSeconds($this->invoice->company->timezone()->utc_offset)->format('Y-m-d');
|
||||
|
||||
@ -149,7 +149,7 @@ class MarkPaid extends AbstractService
|
||||
//$payment->exchange_currency_id = $client_currency; // 23/06/2021
|
||||
$payment->exchange_currency_id = $company_currency;
|
||||
|
||||
$payment->save();
|
||||
$payment->saveQuietly();
|
||||
|
||||
}
|
||||
|
||||
|
@ -226,7 +226,7 @@ class Design extends BaseDesign
|
||||
{
|
||||
if ($this->type === 'statement') {
|
||||
|
||||
$s_date = $this->translateDate($this->options['end_date'], $this->client->date_format(), $this->client->locale());
|
||||
$s_date = $this->translateDate(now()->format($client->company->date_format()), $this->client->date_format(), $this->client->locale());
|
||||
|
||||
return [
|
||||
['element' => 'tr', 'properties' => ['data-ref' => 'statement-label'], 'elements' => [
|
||||
|
@ -37,7 +37,7 @@ class ApplyNumber
|
||||
switch ($this->client->getSetting('counter_number_applied')) {
|
||||
case 'when_saved':
|
||||
$quote = $this->trySaving($quote);
|
||||
// $quote->number = $this->getNextQuoteNumber($this->client, $quote);
|
||||
// $quote->number = $this->getNextQuoteNumber($this->client, $quote);
|
||||
break;
|
||||
case 'when_sent':
|
||||
if ($quote->status_id == Quote::STATUS_SENT) {
|
||||
|
679
app/Services/Report/ProfitLoss.php
Normal file
679
app/Services/Report/ProfitLoss.php
Normal file
@ -0,0 +1,679 @@
|
||||
<?php
|
||||
/**
|
||||
* Invoice Ninja (https://invoiceninja.com).
|
||||
*
|
||||
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||
*
|
||||
* @copyright Copyright (c) 2022. Invoice Ninja LLC (https://invoiceninja.com)
|
||||
*
|
||||
* @license https://www.elastic.co/licensing/elastic-license
|
||||
*/
|
||||
|
||||
namespace App\Services\Report;
|
||||
|
||||
use App\Libraries\Currency\Conversion\CurrencyApi;
|
||||
use App\Libraries\MultiDB;
|
||||
use App\Models\Company;
|
||||
use App\Models\Currency;
|
||||
use App\Models\Expense;
|
||||
use App\Models\Payment;
|
||||
use App\Utils\Ninja;
|
||||
use App\Utils\Number;
|
||||
use Illuminate\Support\Carbon;
|
||||
use Illuminate\Support\Facades\App;
|
||||
use League\Csv\Writer;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
class ProfitLoss
|
||||
{
|
||||
private bool $is_income_billed = true;
|
||||
|
||||
private bool $is_expense_billed = true;
|
||||
|
||||
private bool $is_tax_included = true;
|
||||
|
||||
private $start_date;
|
||||
|
||||
private $end_date;
|
||||
|
||||
private float $income = 0;
|
||||
|
||||
private float $income_taxes = 0;
|
||||
|
||||
private float $credit = 0;
|
||||
|
||||
private float $credit_invoice = 0;
|
||||
|
||||
private float $credit_taxes = 0;
|
||||
|
||||
private array $invoice_payment_map = [];
|
||||
|
||||
private array $expenses = [];
|
||||
|
||||
private array $expense_break_down = [];
|
||||
|
||||
private array $income_map;
|
||||
|
||||
private array $foreign_income = [];
|
||||
|
||||
protected CurrencyApi $currency_api;
|
||||
|
||||
/*
|
||||
payload variables.
|
||||
|
||||
start_date - Y-m-d
|
||||
end_date - Y-m-d
|
||||
date_range -
|
||||
all
|
||||
last7
|
||||
last30
|
||||
this_month
|
||||
last_month
|
||||
this_quarter
|
||||
last_quarter
|
||||
this_year
|
||||
custom
|
||||
is_income_billed - true = Invoiced || false = Payments
|
||||
is_expense_billed - true = Expensed || false = Expenses marked as paid
|
||||
include_tax - true tax_included || false - tax_excluded
|
||||
|
||||
*/
|
||||
|
||||
protected array $payload;
|
||||
|
||||
protected Company $company;
|
||||
|
||||
public function __construct(Company $company, array $payload)
|
||||
{
|
||||
$this->currency_api = new CurrencyApi();
|
||||
|
||||
$this->company = $company;
|
||||
|
||||
$this->payload = $payload;
|
||||
|
||||
$this->setBillingReportType();
|
||||
}
|
||||
|
||||
public function build()
|
||||
{
|
||||
MultiDB::setDb($this->company->db);
|
||||
|
||||
if($this->is_income_billed){ //get invoiced amounts
|
||||
|
||||
$this->filterIncome();
|
||||
|
||||
}else {
|
||||
|
||||
//$this->filterPaymentIncome();
|
||||
$this->filterInvoicePaymentIncome();
|
||||
}
|
||||
|
||||
$this->expenseData()->buildExpenseBreakDown();
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getIncome() :float
|
||||
{
|
||||
return round($this->income,2);
|
||||
}
|
||||
|
||||
public function getIncomeMap() :array
|
||||
{
|
||||
return $this->income_map;
|
||||
}
|
||||
|
||||
public function getIncomeTaxes() :float
|
||||
{
|
||||
return round($this->income_taxes,2);
|
||||
}
|
||||
|
||||
public function getExpenses() :array
|
||||
{
|
||||
return $this->expenses;
|
||||
}
|
||||
|
||||
public function getExpenseBreakDown() :array
|
||||
{
|
||||
ksort($this->expense_break_down);
|
||||
|
||||
return $this->expense_break_down;
|
||||
}
|
||||
|
||||
private function filterIncome()
|
||||
{
|
||||
$invoices = $this->invoiceIncome();
|
||||
|
||||
$this->foreign_income = [];
|
||||
|
||||
$this->income = 0;
|
||||
$this->income_taxes = 0;
|
||||
$this->income_map = $invoices;
|
||||
|
||||
foreach($invoices as $invoice){
|
||||
$this->income += $invoice->net_converted_amount;
|
||||
$this->income_taxes += $invoice->net_converted_taxes;
|
||||
|
||||
|
||||
$currency = Currency::find(intval(str_replace('"','',$invoice->currency_id)));
|
||||
$currency->name = ctrans('texts.currency_'.Str::slug($currency->name, '_'));
|
||||
|
||||
$this->foreign_income[] = ['currency' => $currency->name, 'amount' => $invoice->amount, 'total_taxes' => $invoice->total_taxes];
|
||||
}
|
||||
|
||||
return $this;
|
||||
|
||||
}
|
||||
|
||||
private function filterInvoicePaymentIncome()
|
||||
{
|
||||
|
||||
$this->paymentEloquentIncome();
|
||||
|
||||
foreach($this->invoice_payment_map as $map) {
|
||||
$this->income += $map->amount_payment_paid_converted - $map->tax_amount_converted;
|
||||
$this->income_taxes += $map->tax_amount_converted;
|
||||
|
||||
$this->credit += $map->amount_credit_paid_converted - $map->tax_amount_credit_converted;
|
||||
$this->credit_taxes += $map->tax_amount_credit_converted;
|
||||
}
|
||||
|
||||
// $invoices = $this->invoicePaymentIncome();
|
||||
|
||||
// $this->income = 0;
|
||||
// $this->income_taxes = 0;
|
||||
// $this->income_map = $invoices;
|
||||
|
||||
// foreach($invoices as $invoice){
|
||||
// $this->income += $invoice->net_converted_amount;
|
||||
// $this->income_taxes += $invoice->net_converted_taxes;
|
||||
// }
|
||||
|
||||
return $this;
|
||||
|
||||
}
|
||||
|
||||
private function getForeignIncome() :array
|
||||
{
|
||||
return $this->foreign_income;
|
||||
}
|
||||
|
||||
private function filterPaymentIncome()
|
||||
{
|
||||
$payments = $this->paymentIncome();
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/*
|
||||
//returns an array of objects
|
||||
=> [
|
||||
{#2047
|
||||
+"amount": "706.480000",
|
||||
+"total_taxes": "35.950000",
|
||||
+"currency_id": ""1"",
|
||||
+"net_converted_amount": "670.5300000000",
|
||||
+"net_converted_taxes": "10"
|
||||
},
|
||||
{#2444
|
||||
+"amount": "200.000000",
|
||||
+"total_taxes": "0.000000",
|
||||
+"currency_id": ""23"",
|
||||
+"net_converted_amount": "1.7129479802",
|
||||
+"net_converted_taxes": "10"
|
||||
},
|
||||
{#2654
|
||||
+"amount": "140.000000",
|
||||
+"total_taxes": "40.000000",
|
||||
+"currency_id": ""12"",
|
||||
+"net_converted_amount": "69.3275024282",
|
||||
+"net_converted_taxes": "10"
|
||||
},
|
||||
]
|
||||
*/
|
||||
private function invoiceIncome()
|
||||
{
|
||||
return \DB::select( \DB::raw("
|
||||
SELECT
|
||||
sum(invoices.amount) as amount,
|
||||
sum(invoices.total_taxes) as total_taxes,
|
||||
(sum(invoices.total_taxes) / IFNULL(invoices.exchange_rate, 1)) AS net_converted_taxes,
|
||||
sum(invoices.amount - invoices.total_taxes) as net_amount,
|
||||
IFNULL(JSON_EXTRACT( settings, '$.currency_id' ), :company_currency) AS currency_id,
|
||||
(sum(invoices.amount - invoices.total_taxes) / IFNULL(invoices.exchange_rate, 1)) AS net_converted_amount
|
||||
FROM clients
|
||||
JOIN invoices
|
||||
on invoices.client_id = clients.id
|
||||
WHERE invoices.status_id IN (2,3,4)
|
||||
AND invoices.company_id = :company_id
|
||||
AND invoices.amount > 0
|
||||
AND clients.is_deleted = 0
|
||||
AND invoices.is_deleted = 0
|
||||
AND (invoices.date BETWEEN :start_date AND :end_date)
|
||||
GROUP BY currency_id
|
||||
"), ['company_currency' => $this->company->settings->currency_id, 'company_id' => $this->company->id, 'start_date' => $this->start_date, 'end_date' => $this->end_date] );
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* The income calculation is based on the total payments received during
|
||||
* the selected time period.
|
||||
*
|
||||
* Once we have the payments we iterate through the attached invoices and
|
||||
* we also determine the total taxes paid as our
|
||||
* Profit and loss statement should be net of all taxes
|
||||
*
|
||||
* This calculation also considers partial payments and pro rata's any taxes.
|
||||
*
|
||||
* This calculation also considers exchange rates and we convert (based on the payment exchange rate)
|
||||
* to the native company currency.
|
||||
*/
|
||||
private function paymentEloquentIncome()
|
||||
{
|
||||
|
||||
$this->invoice_payment_map = [];
|
||||
|
||||
Payment::where('company_id', $this->company->id)
|
||||
->whereIn('status_id', [1,4,5])
|
||||
->where('is_deleted', 0)
|
||||
->whereBetween('date', [$this->start_date, $this->end_date])
|
||||
->whereHas('client', function ($query) {
|
||||
$query->where('is_deleted',0);
|
||||
})
|
||||
->with(['company','client'])
|
||||
->cursor()
|
||||
->each(function ($payment){
|
||||
|
||||
$company = $payment->company;
|
||||
$client = $payment->client;
|
||||
|
||||
$map = new \stdClass;
|
||||
$amount_payment_paid = 0;
|
||||
$amount_credit_paid = 0;
|
||||
$amount_payment_paid_converted = 0;
|
||||
$amount_credit_paid_converted = 0;
|
||||
$tax_amount = 0;
|
||||
$tax_amount_converted = 0;
|
||||
$tax_amount_credit = 0;
|
||||
$tax_amount_credit_converted = $tax_amount_credit_converted = 0;
|
||||
|
||||
foreach($payment->paymentables as $pivot)
|
||||
{
|
||||
|
||||
if($pivot->paymentable instanceOf \App\Models\Invoice){
|
||||
|
||||
$invoice = $pivot->paymentable;
|
||||
|
||||
$amount_payment_paid += $pivot->amount - $pivot->refunded;
|
||||
$amount_payment_paid_converted += $amount_payment_paid / ($payment->exchange_rate ?: 1);
|
||||
|
||||
$tax_amount += ($amount_payment_paid / $invoice->amount) * $invoice->total_taxes;
|
||||
$tax_amount_converted += (($amount_payment_paid / $invoice->amount) * $invoice->total_taxes) / $payment->exchange_rate;
|
||||
|
||||
}
|
||||
|
||||
|
||||
if($pivot->paymentable instanceOf \App\Models\Credit){
|
||||
|
||||
$amount_credit_paid += $pivot->amount - $pivot->refunded;
|
||||
$amount_credit_paid_converted += $amount_payment_paid / ($payment->exchange_rate ?: 1);
|
||||
|
||||
$tax_amount_credit += ($amount_payment_paid / $invoice->amount) * $invoice->total_taxes;
|
||||
$tax_amount_credit_converted += (($amount_payment_paid / $invoice->amount) * $invoice->total_taxes) / $payment->exchange_rate;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
$map->amount_payment_paid = $amount_payment_paid;
|
||||
$map->amount_payment_paid_converted = $amount_payment_paid_converted;
|
||||
$map->tax_amount = $tax_amount;
|
||||
$map->tax_amount_converted = $tax_amount_converted;
|
||||
$map->amount_credit_paid = $amount_credit_paid;
|
||||
$map->amount_credit_paid_converted = $amount_credit_paid_converted;
|
||||
$map->tax_amount_credit = $tax_amount_credit;
|
||||
$map->tax_amount_credit_converted = $tax_amount_credit_converted;
|
||||
$map->currency_id = $payment->currency_id;
|
||||
|
||||
$this->invoice_payment_map[] = $map;
|
||||
|
||||
});
|
||||
|
||||
return $this;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
=> [
|
||||
{#2047
|
||||
+"amount": "110.000000",
|
||||
+"total_taxes": "10.0000000000000000",
|
||||
+"net_converted_amount": "110.0000000000",
|
||||
+"net_converted_taxes": "10.00000000000000000000",
|
||||
+"currency_id": ""1"",
|
||||
},
|
||||
{#2444
|
||||
+"amount": "50.000000",
|
||||
+"total_taxes": "4.5454545454545455",
|
||||
+"net_converted_amount": "61.1682150381",
|
||||
+"net_converted_taxes": "5.56074682164393914741",
|
||||
+"currency_id": ""2"",
|
||||
},
|
||||
]
|
||||
*/
|
||||
|
||||
public function getCsv()
|
||||
{
|
||||
|
||||
MultiDB::setDb($this->company->db);
|
||||
App::forgetInstance('translator');
|
||||
App::setLocale($this->company->locale());
|
||||
$t = app('translator');
|
||||
$t->replace(Ninja::transformTranslations($this->company->settings));
|
||||
|
||||
$csv = Writer::createFromString();
|
||||
|
||||
$csv->insertOne([ctrans('texts.profit_and_loss')]);
|
||||
$csv->insertOne([ctrans('texts.company_name'), $this->company->present()->name()]);
|
||||
$csv->insertOne([ctrans('texts.date_range'), Carbon::parse($this->start_date)->format($this->company->date_format()), Carbon::parse($this->end_date)->format($this->company->date_format())]);
|
||||
|
||||
//gross sales ex tax
|
||||
|
||||
$csv->insertOne(['--------------------']);
|
||||
|
||||
$csv->insertOne([ctrans('texts.total_revenue'), Number::formatMoney($this->income, $this->company)]);
|
||||
|
||||
//total taxes
|
||||
|
||||
$csv->insertOne([ctrans('texts.total_taxes'), Number::formatMoney($this->income_taxes, $this->company)]);
|
||||
|
||||
//expense
|
||||
|
||||
$csv->insertOne(['--------------------']);
|
||||
foreach($this->expense_break_down as $expense_breakdown)
|
||||
{
|
||||
$csv->insertOne([$expense_breakdown['category_name'], Number::formatMoney($expense_breakdown['total'], $this->company)]);
|
||||
}
|
||||
//total expense taxes
|
||||
|
||||
$csv->insertOne(['--------------------']);
|
||||
$csv->insertOne([ctrans('texts.total_expenses'), Number::formatMoney(array_sum(array_column($this->expense_break_down, 'total')), $this->company)]);
|
||||
|
||||
$csv->insertOne([ctrans('texts.total_taxes'), Number::formatMoney(array_sum(array_column($this->expense_break_down, 'tax')), $this->company)]);
|
||||
|
||||
|
||||
$csv->insertOne(['--------------------']);
|
||||
$csv->insertOne([ctrans('texts.total_profit'), Number::formatMoney($this->income - array_sum(array_column($this->expense_break_down, 'total')), $this->company)]);
|
||||
|
||||
//net profit
|
||||
|
||||
$csv->insertOne(['--------------------']);
|
||||
$csv->insertOne(['']);
|
||||
$csv->insertOne(['']);
|
||||
|
||||
$csv->insertOne([ctrans('texts.currency'), ctrans('texts.amount'), ctrans('texts.total_taxes')]);
|
||||
foreach($this->foreign_income as $foreign_income)
|
||||
{
|
||||
$csv->insertOne([$foreign_income['currency'], ($foreign_income['amount'] - $foreign_income['total_taxes']), $foreign_income['total_taxes']]);
|
||||
}
|
||||
|
||||
return $csv->toString();
|
||||
|
||||
}
|
||||
|
||||
private function invoicePaymentIncome()
|
||||
{
|
||||
return \DB::select( \DB::raw("
|
||||
SELECT
|
||||
sum(invoices.amount - invoices.balance) as amount,
|
||||
sum(invoices.total_taxes) * ((sum(invoices.amount - invoices.balance)/invoices.amount)) as total_taxes,
|
||||
(sum(invoices.amount - invoices.balance) / IFNULL(invoices.exchange_rate, 1)) AS net_converted_amount,
|
||||
(sum(invoices.total_taxes) * ((sum(invoices.amount - invoices.balance)/invoices.amount)) / IFNULL(invoices.exchange_rate, 1)) AS net_converted_taxes,
|
||||
IFNULL(JSON_EXTRACT( settings, '$.currency_id' ), :company_currency) AS currency_id
|
||||
FROM clients
|
||||
JOIN invoices
|
||||
on invoices.client_id = clients.id
|
||||
WHERE invoices.status_id IN (3,4)
|
||||
AND invoices.company_id = :company_id
|
||||
AND invoices.amount > 0
|
||||
AND clients.is_deleted = 0
|
||||
AND invoices.is_deleted = 0
|
||||
AND (invoices.date BETWEEN :start_date AND :end_date)
|
||||
GROUP BY currency_id
|
||||
"), ['company_currency' => $this->company->settings->currency_id, 'company_id' => $this->company->id, 'start_date' => $this->start_date, 'end_date' => $this->end_date] );
|
||||
}
|
||||
|
||||
/**
|
||||
+"payments": "12260.870000",
|
||||
+"payments_converted": "12260.870000000000",
|
||||
+"currency_id": 1,
|
||||
*/
|
||||
private function paymentIncome()
|
||||
{
|
||||
return \DB::select( \DB::raw("
|
||||
SELECT
|
||||
SUM(coalesce(payments.amount - payments.refunded,0)) as payments,
|
||||
SUM(coalesce(payments.amount - payments.refunded,0)) * IFNULL(payments.exchange_rate ,1) as payments_converted,
|
||||
payments.currency_id as currency_id
|
||||
FROM clients
|
||||
INNER JOIN
|
||||
payments ON
|
||||
clients.id=payments.client_id
|
||||
WHERE payments.status_id IN (1,4,5,6)
|
||||
AND clients.is_deleted = false
|
||||
AND payments.is_deleted = false
|
||||
AND payments.company_id = :company_id
|
||||
AND (payments.date BETWEEN :start_date AND :end_date)
|
||||
GROUP BY currency_id
|
||||
ORDER BY currency_id;
|
||||
"), ['company_id' => $this->company->id, 'start_date' => $this->start_date, 'end_date' => $this->end_date]);
|
||||
|
||||
|
||||
}
|
||||
|
||||
private function expenseData()
|
||||
{
|
||||
|
||||
$expenses = Expense::where('company_id', $this->company->id)
|
||||
->where('is_deleted', 0)
|
||||
->withTrashed()
|
||||
->whereBetween('date', [$this->start_date, $this->end_date])
|
||||
->cursor();
|
||||
|
||||
|
||||
$this->expenses = [];
|
||||
|
||||
foreach($expenses as $expense)
|
||||
{
|
||||
$map = new \stdClass;
|
||||
|
||||
$amount = $expense->amount;
|
||||
|
||||
$map->total = $expense->amount;
|
||||
$map->converted_total = $converted_total = $this->getConvertedTotal($expense->amount, $expense->exchange_rate);
|
||||
$map->tax = $tax = $this->getTax($expense);
|
||||
$map->net_converted_total = $expense->uses_inclusive_taxes ? ( $converted_total - $tax ) : $converted_total;
|
||||
$map->category_id = $expense->category_id;
|
||||
$map->category_name = $expense->category ? $expense->category->name : "No Category Defined";
|
||||
$map->currency_id = $expense->currency_id ?: $expense->company->settings->currency_id;
|
||||
|
||||
$this->expenses[] = $map;
|
||||
|
||||
}
|
||||
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
private function buildExpenseBreakDown()
|
||||
{
|
||||
$data = [];
|
||||
|
||||
foreach($this->expenses as $expense)
|
||||
{
|
||||
if(!array_key_exists($expense->category_id, $data))
|
||||
$data[$expense->category_id] = [];
|
||||
|
||||
if(!array_key_exists('total', $data[$expense->category_id]))
|
||||
$data[$expense->category_id]['total'] = 0;
|
||||
|
||||
if(!array_key_exists('tax', $data[$expense->category_id]))
|
||||
$data[$expense->category_id]['tax'] = 0;
|
||||
|
||||
$data[$expense->category_id]['total'] += $expense->net_converted_total;
|
||||
$data[$expense->category_id]['category_name'] = $expense->category_name;
|
||||
$data[$expense->category_id]['tax'] += $expense->tax;
|
||||
|
||||
}
|
||||
|
||||
$this->expense_break_down = $data;
|
||||
|
||||
return $this;
|
||||
|
||||
}
|
||||
|
||||
private function getTax($expense)
|
||||
{
|
||||
$amount = $expense->amount;
|
||||
//is amount tax
|
||||
|
||||
if($expense->calculate_tax_by_amount)
|
||||
{
|
||||
nlog($expense->tax_amount1);
|
||||
nlog($expense->tax_amount2);
|
||||
nlog($expense->tax_amount3);
|
||||
|
||||
return $expense->tax_amount1 + $expense->tax_amount2 + $expense->tax_amount3;
|
||||
}
|
||||
|
||||
|
||||
if($expense->uses_inclusive_taxes){
|
||||
|
||||
$inclusive = 0;
|
||||
|
||||
$inclusive += ($amount - ($amount / (1 + ($expense->tax_rate1 / 100))));
|
||||
$inclusive += ($amount - ($amount / (1 + ($expense->tax_rate2 / 100))));
|
||||
$inclusive += ($amount - ($amount / (1 + ($expense->tax_rate3 / 100))));
|
||||
|
||||
return round($inclusive,2);
|
||||
|
||||
}
|
||||
|
||||
$exclusive = 0;
|
||||
|
||||
$exclusive += $amount * ($expense->tax_rate1 / 100);
|
||||
$exclusive += $amount * ($expense->tax_rate2 / 100);
|
||||
$exclusive += $amount * ($expense->tax_rate3 / 100);
|
||||
|
||||
|
||||
return $exclusive;
|
||||
|
||||
}
|
||||
|
||||
private function getConvertedTotal($amount, $exchange_rate = 1)
|
||||
{
|
||||
return round(($amount * $exchange_rate) ,2);
|
||||
}
|
||||
|
||||
private function expenseCalcWithTax()
|
||||
{
|
||||
|
||||
return \DB::select( \DB::raw("
|
||||
SELECT sum(expenses.amount) as amount,
|
||||
IFNULL(expenses.currency_id, :company_currency) as currency_id
|
||||
FROM expenses
|
||||
WHERE expenses.is_deleted = 0
|
||||
AND expenses.company_id = :company_id
|
||||
AND (expenses.date BETWEEN :start_date AND :end_date)
|
||||
GROUP BY currency_id
|
||||
"), ['company_currency' => $this->company->settings->currency_id, 'company_id' => $this->company->id, 'start_date' => $this->start_date, 'end_date' => $this->end_date] );
|
||||
|
||||
}
|
||||
|
||||
private function setBillingReportType()
|
||||
{
|
||||
|
||||
if(array_key_exists('is_income_billed', $this->payload))
|
||||
$this->is_income_billed = boolval($this->payload['is_income_billed']);
|
||||
|
||||
if(array_key_exists('is_expense_billed', $this->payload))
|
||||
$this->is_expense_billed = boolval($this->payload['is_expense_billed']);
|
||||
|
||||
if(array_key_exists('include_tax', $this->payload))
|
||||
$this->is_tax_included = boolval($this->payload['include_tax']);
|
||||
|
||||
$this->addDateRange();
|
||||
|
||||
return $this;
|
||||
|
||||
}
|
||||
|
||||
private function addDateRange()
|
||||
{
|
||||
$date_range = 'this_year';
|
||||
|
||||
if(array_key_exists('date_range', $this->payload))
|
||||
$date_range = $this->payload['date_range'];
|
||||
|
||||
try{
|
||||
|
||||
$custom_start_date = Carbon::parse($this->payload['start_date']);
|
||||
$custom_end_date = Carbon::parse($this->payload['end_date']);
|
||||
|
||||
}
|
||||
catch(\Exception $e){
|
||||
|
||||
$custom_start_date = now()->startOfYear();
|
||||
$custom_end_date = now();
|
||||
|
||||
}
|
||||
|
||||
switch ($date_range) {
|
||||
|
||||
case 'all':
|
||||
$this->start_date = now()->subYears(50);
|
||||
$this->end_date = now();
|
||||
// return $query;
|
||||
case 'last7':
|
||||
$this->start_date = now()->subDays(7);
|
||||
$this->end_date = now();
|
||||
// return $query->whereBetween($this->date_key, [now()->subDays(7), now()])->orderBy($this->date_key, 'ASC');
|
||||
case 'last30':
|
||||
$this->start_date = now()->subDays(30);
|
||||
$this->end_date = now();
|
||||
// return $query->whereBetween($this->date_key, [now()->subDays(30), now()])->orderBy($this->date_key, 'ASC');
|
||||
case 'this_month':
|
||||
$this->start_date = now()->startOfMonth();
|
||||
$this->end_date = now();
|
||||
//return $query->whereBetween($this->date_key, [now()->startOfMonth(), now()])->orderBy($this->date_key, 'ASC');
|
||||
case 'last_month':
|
||||
$this->start_date = now()->startOfMonth()->subMonth();
|
||||
$this->end_date = now()->startOfMonth()->subMonth()->endOfMonth();
|
||||
//return $query->whereBetween($this->date_key, [now()->startOfMonth()->subMonth(), now()->startOfMonth()->subMonth()->endOfMonth()])->orderBy($this->date_key, 'ASC');
|
||||
case 'this_quarter':
|
||||
$this->start_date = (new \Carbon\Carbon('-3 months'))->firstOfQuarter();
|
||||
$this->end_date = (new \Carbon\Carbon('-3 months'))->lastOfQuarter();
|
||||
//return $query->whereBetween($this->date_key, [(new \Carbon\Carbon('-3 months'))->firstOfQuarter(), (new \Carbon\Carbon('-3 months'))->lastOfQuarter()])->orderBy($this->date_key, 'ASC');
|
||||
case 'last_quarter':
|
||||
$this->start_date = (new \Carbon\Carbon('-6 months'))->firstOfQuarter();
|
||||
$this->end_date = (new \Carbon\Carbon('-6 months'))->lastOfQuarter();
|
||||
//return $query->whereBetween($this->date_key, [(new \Carbon\Carbon('-6 months'))->firstOfQuarter(), (new \Carbon\Carbon('-6 months'))->lastOfQuarter()])->orderBy($this->date_key, 'ASC');
|
||||
case 'this_year':
|
||||
$this->start_date = now()->startOfYear();
|
||||
$this->end_date = now();
|
||||
//return $query->whereBetween($this->date_key, [now()->startOfYear(), now()])->orderBy($this->date_key, 'ASC');
|
||||
case 'custom':
|
||||
$this->start_date = $custom_start_date;
|
||||
$this->end_date = $custom_end_date;
|
||||
//return $query->whereBetween($this->date_key, [$custom_start_date, $custom_end_date])->orderBy($this->date_key, 'ASC');
|
||||
default:
|
||||
$this->start_date = now()->startOfYear();
|
||||
$this->end_date = now();
|
||||
// return $query->whereBetween($this->date_key, [now()->startOfYear(), now()])->orderBy($this->date_key, 'ASC');
|
||||
|
||||
}
|
||||
|
||||
return $this;
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -40,18 +40,6 @@ class CompanyFactory extends Factory
|
||||
'default_password_timeout' => 30*60000,
|
||||
'enabled_modules' => config('ninja.enabled_modules'),
|
||||
'custom_fields' => (object) [
|
||||
//'invoice1' => 'Custom Date|date',
|
||||
// 'invoice2' => '2|switch',
|
||||
// 'invoice3' => '3|',
|
||||
// 'invoice4' => '4',
|
||||
// 'client1'=>'1',
|
||||
// 'client2'=>'2',
|
||||
// 'client3'=>'3|date',
|
||||
// 'client4'=>'4|switch',
|
||||
// 'company1'=>'1|date',
|
||||
// 'company2'=>'2|switch',
|
||||
// 'company3'=>'3',
|
||||
// 'company4'=>'4',
|
||||
],
|
||||
];
|
||||
}
|
||||
|
@ -22,7 +22,7 @@ $LANG = array(
|
||||
'currency_id' => 'Währung',
|
||||
'size_id' => 'Firmengröße',
|
||||
'industry_id' => 'Branche',
|
||||
'private_notes' => 'Private Notizen',
|
||||
'private_notes' => 'Interne Notizen',
|
||||
'invoice' => 'Rechnung',
|
||||
'client' => 'Kunde',
|
||||
'invoice_date' => 'Rechnungsdatum',
|
||||
@ -115,7 +115,7 @@ $LANG = array(
|
||||
'upcoming_invoices' => 'Ausstehende Rechnungen',
|
||||
'average_invoice' => 'Durchschnittlicher Rechnungsbetrag',
|
||||
'archive' => 'Archivieren',
|
||||
'delete' => 'löschen',
|
||||
'delete' => 'Löschen',
|
||||
'archive_client' => 'Kunde archivieren',
|
||||
'delete_client' => 'Kunde löschen',
|
||||
'archive_payment' => 'Zahlung archivieren',
|
||||
@ -172,7 +172,7 @@ $LANG = array(
|
||||
'localization' => 'Lokalisierung',
|
||||
'remove_logo' => 'Logo entfernen',
|
||||
'logo_help' => 'Unterstützt: JPEG, GIF und PNG',
|
||||
'payment_gateway' => 'Zahlungseingang',
|
||||
'payment_gateway' => 'Zahlungs-Gateway',
|
||||
'gateway_id' => 'Zahlungsanbieter',
|
||||
'email_notifications' => 'E-Mail Benachrichtigungen',
|
||||
'email_sent' => 'Benachrichtigen, wenn eine Rechnung <strong>versendet</strong> wurde',
|
||||
@ -246,7 +246,7 @@ $LANG = array(
|
||||
'payment_subject' => 'Zahlungseingang',
|
||||
'payment_message' => 'Vielen Dank für Ihre Zahlung von :amount.',
|
||||
'email_salutation' => 'Sehr geehrte/r :name,',
|
||||
'email_signature' => 'Mit freundlichen Grüßen,',
|
||||
'email_signature' => 'Mit freundlichen Grüßen',
|
||||
'email_from' => 'Das InvoiceNinja Team',
|
||||
'invoice_link_message' => 'Um deine Kundenrechnung anzuschauen, klicke auf den folgenden Link:',
|
||||
'notification_invoice_paid_subject' => 'Die Rechnung :invoice wurde von :client bezahlt.',
|
||||
@ -272,13 +272,13 @@ $LANG = array(
|
||||
'erase_data' => 'Ihr Konto ist nicht registriert, diese Aktion wird Ihre Daten unwiderruflich löschen.',
|
||||
'password' => 'Passwort',
|
||||
'pro_plan_product' => 'Pro Plan',
|
||||
'pro_plan_success' => 'Danke, dass Sie Invoice Ninja\'s Pro gewählt haben!<p/> <br/>
|
||||
'pro_plan_success' => 'Danke, dass Sie Invoice Ninja\'s Pro-Tarif gewählt haben!<p/> <br/>
|
||||
<b>Nächste Schritte</b>Eine bezahlbare Rechnung wurde an die Mailadresse,
|
||||
welche mit Ihrem Account verbunden ist, geschickt. Um alle der umfangreichen
|
||||
Pro Funktionen freizuschalten, folgen Sie bitte den Anweisungen in der Rechnung um ein Jahr
|
||||
die Pro Funktionen zu nutzen.
|
||||
Sie finden die Rechnung nicht? Sie benötigen weitere Hilfe? Wir helfen gerne
|
||||
-- schicken Sie uns doch eine Email an contact@invoice-ninja.com',
|
||||
-- schicken Sie uns doch eine E-Mail an contact@invoice-ninja.com',
|
||||
'unsaved_changes' => 'Es liegen ungespeicherte Änderungen vor',
|
||||
'custom_fields' => 'Benutzerdefinierte Felder',
|
||||
'company_fields' => 'Firmenfelder',
|
||||
@ -504,7 +504,7 @@ $LANG = array(
|
||||
'notification_quote_approved_subject' => 'Angebot :invoice wurde von :client angenommen.',
|
||||
'notification_quote_approved' => 'Der folgende Kunde :client nahm das Angebot :invoice über :amount an.',
|
||||
'resend_confirmation' => 'Bestätigungsmail erneut senden',
|
||||
'confirmation_resent' => 'Bestätigungsemail wurde erneut versendet',
|
||||
'confirmation_resent' => 'Bestätigungs-E-Mail wurde erneut versendet',
|
||||
'gateway_help_42' => ':link zum Registrieren auf BitPay.<br/>Hinweis: benutze einen Legacy API Key, keinen API token.',
|
||||
'payment_type_credit_card' => 'Kreditkarte',
|
||||
'payment_type_paypal' => 'PayPal',
|
||||
@ -602,7 +602,7 @@ $LANG = array(
|
||||
'pro_plan_feature5' => 'Multi-Benutzer Zugriff & Aktivitätstracking',
|
||||
'pro_plan_feature6' => 'Angebote & pro-forma Rechnungen erstellen',
|
||||
'pro_plan_feature7' => 'Rechungstitelfelder und Nummerierung anpassen',
|
||||
'pro_plan_feature8' => 'PDFs an Kunden-Emails anhängen',
|
||||
'pro_plan_feature8' => 'PDFs an Kunden-E-Mails anhängen',
|
||||
'resume' => 'Fortfahren',
|
||||
'break_duration' => 'Pause',
|
||||
'edit_details' => 'Details bearbeiten',
|
||||
@ -645,8 +645,8 @@ $LANG = array(
|
||||
'styles' => 'Stile',
|
||||
'defaults' => 'Standards',
|
||||
'margins' => 'Außenabstände',
|
||||
'header' => 'Kopf',
|
||||
'footer' => 'Fußzeile',
|
||||
'header' => 'Header-Code',
|
||||
'footer' => 'Footer-Code',
|
||||
'custom' => 'Benutzerdefiniert',
|
||||
'invoice_to' => 'Rechnung an',
|
||||
'invoice_no' => 'Rechnung Nr.',
|
||||
@ -689,9 +689,9 @@ $LANG = array(
|
||||
'auto_bill' => 'Automatische Verrechnung',
|
||||
'military_time' => '24-Stunden-Zeit',
|
||||
'last_sent' => 'Zuletzt versendet',
|
||||
'reminder_emails' => 'Erinnerungs-Emails',
|
||||
'quote_reminder_emails' => 'Angebot Erinngerungs Emails',
|
||||
'templates_and_reminders' => 'Vorlagen & Erinnerungen',
|
||||
'reminder_emails' => 'Mahnungs-E-Mails',
|
||||
'quote_reminder_emails' => 'Angebots-Erinngerungs-E-Mails',
|
||||
'templates_and_reminders' => 'Vorlagen & Mahnungen',
|
||||
'subject' => 'Betreff',
|
||||
'body' => 'Inhalt',
|
||||
'first_reminder' => 'Erste Erinnerung',
|
||||
@ -889,9 +889,9 @@ $LANG = array(
|
||||
'custom_invoice_charges_helps' => 'Füge ein Rechnungsgebührenfeld hinzu. Erfasse die Kosten, wenn eine neue Rechnung erstellt wird und addiere sie in den Zwischensummen der Rechnung.',
|
||||
'token_expired' => 'Validierungstoken ist abgelaufen. Bitte probieren Sie es erneut.',
|
||||
'invoice_link' => 'Link zur Rechnung',
|
||||
'button_confirmation_message' => 'Klicke um Deine Email zu bestätigen',
|
||||
'button_confirmation_message' => 'Bestätige deine E-Mail-Adresse.',
|
||||
'confirm' => 'Bestätigen',
|
||||
'email_preferences' => 'Email Einstellungen',
|
||||
'email_preferences' => 'E-Mail-Einstellungen',
|
||||
'created_invoices' => ':count Rechnung(en) erfolgreich erstellt',
|
||||
'next_invoice_number' => 'Die nächste Rechnungsnummer ist :number.',
|
||||
'next_quote_number' => 'Die nächste Angebotsnummer ist :number.',
|
||||
@ -1048,13 +1048,13 @@ $LANG = array(
|
||||
'invitation_status_sent' => 'Gesendet',
|
||||
'invitation_status_opened' => 'Geöffnet',
|
||||
'invitation_status_viewed' => 'Gesehen',
|
||||
'email_error_inactive_client' => 'Emails können nicht zu inaktiven Kunden gesendet werden',
|
||||
'email_error_inactive_contact' => 'Emails können nicht zu inaktiven Kontakten gesendet werden',
|
||||
'email_error_inactive_invoice' => 'Emails können nicht zu inaktiven Rechnungen gesendet werden',
|
||||
'email_error_inactive_proposal' => 'Emails können nicht für inaktive Vorschläge gesendet werden',
|
||||
'email_error_user_unregistered' => 'Bitte registrieren Sie sich um Emails zu versenden',
|
||||
'email_error_user_unconfirmed' => 'Bitte bestätigen Sie Ihr Konto um Emails zu senden',
|
||||
'email_error_invalid_contact_email' => 'Ungültige Kontakt Email Adresse',
|
||||
'email_error_inactive_client' => 'E-Mails können nicht zu inaktiven Kunden gesendet werden',
|
||||
'email_error_inactive_contact' => 'E-Mails können nicht zu inaktiven Kontakten gesendet werden',
|
||||
'email_error_inactive_invoice' => 'E-Mails können nicht zu inaktiven Rechnungen gesendet werden',
|
||||
'email_error_inactive_proposal' => 'E-Mails können nicht für inaktive Vorschläge gesendet werden',
|
||||
'email_error_user_unregistered' => 'Bitte registrieren Sie sich um E-Mails zu versenden',
|
||||
'email_error_user_unconfirmed' => 'Bitte bestätigen Sie Ihr Konto um E-Mails zu versenden',
|
||||
'email_error_invalid_contact_email' => 'Ungültige Kontakt-E-Mail-Adresse',
|
||||
|
||||
'navigation' => 'Navigation',
|
||||
'list_invoices' => 'Rechnungen anzeigen',
|
||||
@ -1316,7 +1316,7 @@ Sobald Sie die Beträge erhalten haben, kommen Sie bitte wieder zurück zu diese
|
||||
'enabled' => 'Aktiviert',
|
||||
'paypal' => 'PayPal',
|
||||
'braintree_enable_paypal' => 'PayPal Zahlungen mittels BrainTree aktivieren',
|
||||
'braintree_paypal_disabled_help' => 'Das PayPal Gateway bearbeitet PayPal-Zahlungen',
|
||||
'braintree_paypal_disabled_help' => 'Das PayPal-Gateway bearbeitet gerade PayPal-Zahlungen',
|
||||
'braintree_paypal_help' => 'Sie müssen auch :link',
|
||||
'braintree_paypal_help_link_text' => 'PayPal Konto mit BrainTree verknüpfen',
|
||||
'token_billing_braintree_paypal' => 'Zahlungsdetails speichern',
|
||||
@ -1339,7 +1339,7 @@ Sobald Sie die Beträge erhalten haben, kommen Sie bitte wieder zurück zu diese
|
||||
'wepay_description_help' => 'Zweck des Kontos.',
|
||||
'wepay_tos_agree' => 'Ich stimme den :link zu',
|
||||
'wepay_tos_link_text' => 'WePay Servicebedingungen',
|
||||
'resend_confirmation_email' => 'Bestätigungsemail nochmal senden',
|
||||
'resend_confirmation_email' => 'Bestätigungs-E-Mail nochmal senden',
|
||||
'manage_account' => 'Account managen',
|
||||
'action_required' => 'Handeln erforderlich',
|
||||
'finish_setup' => 'Setup abschliessen',
|
||||
@ -1846,7 +1846,7 @@ Sobald Sie die Beträge erhalten haben, kommen Sie bitte wieder zurück zu diese
|
||||
'buy_now_buttons_disabled' => 'Diese Funktion setzt voraus, dass ein Produkt erstellt und ein Zahlungs-Gateway konfiguriert wurde.',
|
||||
'enable_buy_now_buttons_help' => 'Aktiviere Unterstützung für "Kaufe jetzt"-Buttons',
|
||||
'changes_take_effect_immediately' => 'Anmerkung: Änderungen treten sofort in Kraft',
|
||||
'wepay_account_description' => 'Zahlungsanbieter für Invoice Ninja',
|
||||
'wepay_account_description' => 'Zahlungs-Gateway für Invoice Ninja',
|
||||
'payment_error_code' => 'Bei der Bearbeitung Ihrer Zahlung [:code] gab es einen Fehler. Bitte versuchen Sie es später erneut.',
|
||||
'standard_fees_apply' => 'Standardgebühren werden erhoben: 2,9% + 0,25€ pro erfolgreicher Belastung bei nicht-europäischen Kreditkarten und 1,4% + 0,25€ bei europäischen Kreditkarten.',
|
||||
'limit_import_rows' => 'Daten müssen in Stapeln von :count Zeilen oder weniger importiert werden',
|
||||
@ -1986,38 +1986,6 @@ Sobald Sie die Beträge erhalten haben, kommen Sie bitte wieder zurück zu diese
|
||||
'authorization' => 'Genehmigung',
|
||||
'signed' => 'unterzeichnet',
|
||||
|
||||
// BlueVine
|
||||
'bluevine_promo' => 'Factoring und Bonitätsauskünfte von BlueVine bestellen.',
|
||||
'bluevine_modal_label' => 'Anmelden mit BlueVine',
|
||||
'bluevine_modal_text' => '<h3>Schnelle Finanzierung ohne Papierkram.</h3>
|
||||
<ul><li>Flexible Bonitätsprüfung und Factoring.</li></ul>',
|
||||
'bluevine_create_account' => 'Konto erstellen',
|
||||
'quote_types' => 'Angebot erhalten für',
|
||||
'invoice_factoring' => 'Factoring',
|
||||
'line_of_credit' => 'Bonitätsprüfung',
|
||||
'fico_score' => 'Ihre FICO Bewertung',
|
||||
'business_inception' => 'Gründungsdatum',
|
||||
'average_bank_balance' => 'durchschnittlicher Kontostand',
|
||||
'annual_revenue' => 'Jahresertrag',
|
||||
'desired_credit_limit_factoring' => 'Gewünschtes Factoring Limit',
|
||||
'desired_credit_limit_loc' => 'gewünschter Kreditrahmen',
|
||||
'desired_credit_limit' => 'gewünschtes Kreditlimit',
|
||||
'bluevine_credit_line_type_required' => 'Sie müssen mindestens eine auswählen',
|
||||
'bluevine_field_required' => 'Dies ist ein Pflichtfeld',
|
||||
'bluevine_unexpected_error' => 'Ein unerwarteter Fehler ist aufgetreten.',
|
||||
'bluevine_no_conditional_offer' => 'Mehr Information ist vonnöten um ein Angebot erstellen zu können. Bitte klicken Sie unten auf Weiter.',
|
||||
'bluevine_invoice_factoring' => 'Factoring',
|
||||
'bluevine_conditional_offer' => 'Freibleibendes Angebot',
|
||||
'bluevine_credit_line_amount' => 'Kreditline',
|
||||
'bluevine_advance_rate' => 'Finanzierungsanteil',
|
||||
'bluevine_weekly_discount_rate' => 'Wöchentlicher Rabatt',
|
||||
'bluevine_minimum_fee_rate' => 'Minimale Gebühr',
|
||||
'bluevine_line_of_credit' => 'Kreditline',
|
||||
'bluevine_interest_rate' => 'Zinssatz',
|
||||
'bluevine_weekly_draw_rate' => 'Wöchtentliche Rückzahlungsquote',
|
||||
'bluevine_continue' => 'Weiter zu BlueVine',
|
||||
'bluevine_completed' => 'BlueVine Anmeldung abgeschlossen',
|
||||
|
||||
'vendor_name' => 'Lieferant',
|
||||
'entity_state' => 'Status',
|
||||
'client_created_at' => 'Erstellungsdatum',
|
||||
@ -2286,8 +2254,8 @@ Sobald Sie die Beträge erhalten haben, kommen Sie bitte wieder zurück zu diese
|
||||
'plan_price' => 'Tarifkosten',
|
||||
'wrong_confirmation' => 'Falscher Bestätigungscode',
|
||||
'oauth_taken' => 'Dieses Konto ist bereits registriert',
|
||||
'emailed_payment' => 'Zahlungs eMail erfolgreich gesendet',
|
||||
'email_payment' => 'Sende Zahlungs eMail',
|
||||
'emailed_payment' => 'Zahlungs-E-Mail erfolgreich gesendet',
|
||||
'email_payment' => 'Sende Zahlungs-E-Mail',
|
||||
'invoiceplane_import' => 'Benutzer :link für die Datenmigration von InvoicePlane.',
|
||||
'duplicate_expense_warning' => 'Achtung: :link evtl. schon vorhanden.',
|
||||
'expense_link' => 'Ausgabe',
|
||||
@ -2568,7 +2536,7 @@ Sobald Sie die Beträge erhalten haben, kommen Sie bitte wieder zurück zu diese
|
||||
'time_hr' => 'Stunde',
|
||||
'time_hrs' => 'Stunden',
|
||||
'clear' => 'Löschen',
|
||||
'warn_payment_gateway' => 'Hinweis: Die Annahme von Online-Zahlungen erfordert einen Zahlungsanbieter. Zum hinzufügen :link.',
|
||||
'warn_payment_gateway' => 'Hinweis: Die Annahme von Online-Zahlungen erfordert ein Zahlungs-Gateway. Zum hinzufügen :link.',
|
||||
'task_rate' => 'Kosten für Tätigkeit',
|
||||
'task_rate_help' => 'Legen Sie den Standardtarif für fakturierte Aufgaben fest.',
|
||||
'past_due' => 'Überfällig',
|
||||
@ -2687,10 +2655,10 @@ Sobald Sie die Beträge erhalten haben, kommen Sie bitte wieder zurück zu diese
|
||||
'module_task' => 'Aufgaben und Projekte',
|
||||
'module_expense' => 'Ausgaben & Lieferanten',
|
||||
'module_ticket' => 'Tickets',
|
||||
'reminders' => 'Erinnerungen',
|
||||
'send_client_reminders' => 'E-Mail Erinnerungen versenden',
|
||||
'reminders' => 'Mahnungen',
|
||||
'send_client_reminders' => 'Mahnung per E-Mail versenden',
|
||||
'can_view_tasks' => 'Aufgaben sind im Portal sichtbar',
|
||||
'is_not_sent_reminders' => 'Erinnerungen werden nicht gesendet',
|
||||
'is_not_sent_reminders' => 'Mahnungen werden nicht versendet',
|
||||
'promotion_footer' => 'Ihre Promotion läuft bald ab, :link, um jetzt ein Upgrade durchzuführen.',
|
||||
'unable_to_delete_primary' => 'Hinweis: Um diese Firma zu löschen, löschen Sie zunächst alle verknüpften Unternehmen.',
|
||||
'please_register' => 'Bitte erstellen Sie sich einen Account',
|
||||
@ -2853,7 +2821,7 @@ Sobald Sie die Beträge erhalten haben, kommen Sie bitte wieder zurück zu diese
|
||||
'accept' => 'Akzeptieren',
|
||||
'accepted_terms' => 'Die neuesten Nutzungsbedingungen wurden akzeptiert.',
|
||||
'invalid_url' => 'Ungültige URL',
|
||||
'workflow_settings' => 'Workflow Einstellungen',
|
||||
'workflow_settings' => 'Workflow-Einstellungen',
|
||||
'auto_email_invoice' => 'Automatische Email',
|
||||
'auto_email_invoice_help' => 'Senden Sie wiederkehrende Rechnungen automatisch per E-Mail, wenn sie erstellt werden.',
|
||||
'auto_archive_invoice' => 'Automatisches Archiv',
|
||||
@ -2872,7 +2840,7 @@ Sobald Sie die Beträge erhalten haben, kommen Sie bitte wieder zurück zu diese
|
||||
'purge_client_warning' => 'Alle zugehörigen Datensätze (Rechnungen, Aufgaben, Ausgaben, Dokumente usw.) werden ebenfalls gelöscht.',
|
||||
'clone_product' => 'Produkt duplizieren',
|
||||
'item_details' => 'Artikeldetails',
|
||||
'send_item_details_help' => 'Senden Sie die Einzelpostendetails an das Zahlungsportal.',
|
||||
'send_item_details_help' => 'Senden Sie die Einzelpostendetails an das Zahlungs-Gateway.',
|
||||
'view_proposal' => 'Vorschlag ansehen',
|
||||
'view_in_portal' => 'Im Portal anzeigen',
|
||||
'cookie_message' => 'Diese Website verwendet Cookies, um sicherzustellen, dass Sie das beste Ergebnis auf unserer Website erzielen.',
|
||||
@ -2974,7 +2942,7 @@ Sobald Sie die Beträge erhalten haben, kommen Sie bitte wieder zurück zu diese
|
||||
'size' => 'Größe',
|
||||
'net' => 'Netto',
|
||||
'show_tasks' => 'Aufgaben anzeigen',
|
||||
'email_reminders' => 'E-Mail Erinnerungen',
|
||||
'email_reminders' => 'Mahnungs-E-Mail',
|
||||
'reminder1' => 'Erste Erinnerung',
|
||||
'reminder2' => 'Zweite Erinnerung',
|
||||
'reminder3' => 'Dritte Erinnerung',
|
||||
@ -3217,7 +3185,7 @@ Sobald Sie die Beträge erhalten haben, kommen Sie bitte wieder zurück zu diese
|
||||
'surcharge_field' => 'Zuschlagsfeld',
|
||||
'company_value' => 'Firmenwert',
|
||||
'credit_field' => 'Kredit-Feld',
|
||||
'payment_field' => 'Zahlungs-Feld',
|
||||
'payment_field' => 'Zahlungsfeld',
|
||||
'group_field' => 'Gruppen-Feld',
|
||||
'number_counter' => 'Nummernzähler',
|
||||
'number_pattern' => 'Nummernschema',
|
||||
@ -3256,7 +3224,7 @@ Sobald Sie die Beträge erhalten haben, kommen Sie bitte wieder zurück zu diese
|
||||
'ocde' => 'Code',
|
||||
'date_format' => 'Datumsformat',
|
||||
'datetime_format' => 'Datums-/Zeitformat',
|
||||
'send_reminders' => 'Erinnerungen senden',
|
||||
'send_reminders' => 'Mahnung senden',
|
||||
'timezone' => 'Zeitzone',
|
||||
'filtered_by_group' => 'Gefiltert nach Gruppe',
|
||||
'filtered_by_invoice' => 'Gefiltert nach Rechnung',
|
||||
@ -3274,7 +3242,7 @@ Sobald Sie die Beträge erhalten haben, kommen Sie bitte wieder zurück zu diese
|
||||
'upload_logo' => 'Logo hochladen',
|
||||
'uploaded_logo' => 'Logo erfolgreich hochgeladen',
|
||||
'saved_settings' => 'Einstellungen erfolgreich gespeichert',
|
||||
'device_settings' => 'Geräteeinstellungen',
|
||||
'device_settings' => 'Geräte-Einstellungen',
|
||||
'credit_cards_and_banks' => 'Kreditkarten & Banken',
|
||||
'price' => 'Preis',
|
||||
'email_sign_up' => 'E-Mail-Registrierung',
|
||||
@ -3454,9 +3422,9 @@ Sobald Sie die Beträge erhalten haben, kommen Sie bitte wieder zurück zu diese
|
||||
'default_tax_rate_2' => 'Standard-Steuersatz 2',
|
||||
'default_tax_name_3' => 'Standard-Steuername 3',
|
||||
'default_tax_rate_3' => 'Standard-Steuersatz 3',
|
||||
'email_subject_invoice' => 'EMail Rechnung Betreff',
|
||||
'email_subject_quote' => 'EMail Angebot Betreff',
|
||||
'email_subject_payment' => 'EMail Zahlung Betreff',
|
||||
'email_subject_invoice' => 'E-Mail Rechnung Betreff',
|
||||
'email_subject_quote' => 'E-Mail Angebot Betreff',
|
||||
'email_subject_payment' => 'E-Mail Zahlung Betreff',
|
||||
'switch_list_table' => 'Listenansicht umschalten',
|
||||
'client_city' => 'Kunden-Stadt',
|
||||
'client_state' => 'Kunden-Bundesland/Kanton',
|
||||
@ -3544,7 +3512,7 @@ Sobald Sie die Beträge erhalten haben, kommen Sie bitte wieder zurück zu diese
|
||||
'clone_to_credit' => 'Duplizieren in Gutschrift',
|
||||
'emailed_credit' => 'Guthaben erfolgreich per E-Mail versendet',
|
||||
'marked_credit_as_sent' => 'Guthaben erfolgreich als versendet markiert',
|
||||
'email_subject_payment_partial' => 'EMail Teilzahlung Betreff',
|
||||
'email_subject_payment_partial' => 'E-Mail Teilzahlung Betreff',
|
||||
'is_approved' => 'Wurde angenommen',
|
||||
'migration_went_wrong' => 'Upps, da ist etwas schiefgelaufen! Stellen Sie sicher, dass Sie InvoiceNinja v5 richtig eingerichtet haben, bevor Sie die Migration starten.',
|
||||
'cross_migration_message' => 'Kontoübergreifende Migration ist nicht erlaubt. Mehr Informationen finden Sie hier:
|
||||
@ -3591,7 +3559,7 @@ https://invoiceninja.github.io/docs/migration/#troubleshooting',
|
||||
'search_users' => 'Suche Benutzer',
|
||||
'search_tax_rates' => 'Suche Steuersatz',
|
||||
'search_tasks' => 'Suche Aufgaben',
|
||||
'search_settings' => 'Suche Einstellungen',
|
||||
'search_settings' => 'Such-Einstellungen',
|
||||
'search_projects' => 'Suche nach Projekten',
|
||||
'search_expenses' => 'Suche Ausgaben',
|
||||
'search_payments' => 'Suche Zahlungen',
|
||||
@ -3652,7 +3620,7 @@ https://invoiceninja.github.io/docs/migration/#troubleshooting',
|
||||
'gross' => 'Gesamtbetrag',
|
||||
'net_amount' => 'Netto Betrag',
|
||||
'net_balance' => 'Netto Betrag',
|
||||
'client_settings' => 'Kundeneinstellungen',
|
||||
'client_settings' => 'Kunden-Einstellungen',
|
||||
'selected_invoices' => 'Ausgewählte Rechnungen',
|
||||
'selected_payments' => 'Ausgewählte Zahlungen',
|
||||
'selected_quotes' => 'Ausgewählte Angebote',
|
||||
@ -3724,16 +3692,16 @@ https://invoiceninja.github.io/docs/migration/#troubleshooting',
|
||||
'mark_invoiceable_help' => 'Ermögliche diese Ausgabe in Rechnung zu stellen',
|
||||
'add_documents_to_invoice_help' => 'Dokumente sichtbar machen',
|
||||
'convert_currency_help' => 'Wechselkurs setzen',
|
||||
'expense_settings' => 'Ausgaben Einstellungen',
|
||||
'expense_settings' => 'Ausgaben-Einstellungen',
|
||||
'clone_to_recurring' => 'Duplizieren zu Widerkehrend',
|
||||
'crypto' => 'Verschlüsselung',
|
||||
'user_field' => 'Benutzer Feld',
|
||||
'user_field' => 'Benutzerfeld',
|
||||
'variables' => 'Variablen',
|
||||
'show_password' => 'Zeige Passwort',
|
||||
'hide_password' => 'Verstecke Passwort',
|
||||
'copy_error' => 'Kopier Fehler',
|
||||
'capture_card' => 'Zahlungsmittel für die weitere Verwendung speichern',
|
||||
'auto_bill_enabled' => 'Automatische Rechnungsstellung aktivieren',
|
||||
'auto_bill_enabled' => 'Automatische Bezahlung aktivieren',
|
||||
'total_taxes' => 'Gesamt Steuern',
|
||||
'line_taxes' => 'Belegposition Steuer',
|
||||
'total_fields' => 'Gesamt Felder',
|
||||
@ -3741,7 +3709,7 @@ https://invoiceninja.github.io/docs/migration/#troubleshooting',
|
||||
'started_recurring_invoice' => 'Wiederkehrende Rechnung erfolgreich gestartet',
|
||||
'resumed_recurring_invoice' => 'Wiederkehrende Rechnung erfolgreich fortgesetzt',
|
||||
'gateway_refund' => 'Zahlungsanbieter Rückerstattung',
|
||||
'gateway_refund_help' => 'Bearbeite die Rückerstattung über den Zahlungsanbieter',
|
||||
'gateway_refund_help' => 'Rückerstattung über das Zahlungs-Gateway abwickeln',
|
||||
'due_date_days' => 'Fälligkeitsdatum',
|
||||
'paused' => 'Pausiert',
|
||||
'day_count' => 'Tag :count',
|
||||
@ -3785,7 +3753,7 @@ https://invoiceninja.github.io/docs/migration/#troubleshooting',
|
||||
'invoice_task_timelog_help' => 'Zeitdetails in der Rechnungsposition ausweisen',
|
||||
'auto_start_tasks_help' => 'Beginne Aufgabe vor dem Speichern',
|
||||
'configure_statuses' => 'Stati bearbeiten',
|
||||
'task_settings' => 'Aufgaben Einstellungen',
|
||||
'task_settings' => 'Aufgaben-Einstellungen',
|
||||
'configure_categories' => 'Kategorien bearbeiten',
|
||||
'edit_expense_category' => 'Ausgaben Kategorie bearbeiten',
|
||||
'removed_expense_category' => 'Ausgaben Kategorie erfolgreich entfernt',
|
||||
@ -3924,7 +3892,7 @@ https://invoiceninja.github.io/docs/migration/#troubleshooting',
|
||||
'before_taxes' => 'Vor Steuern',
|
||||
'after_taxes' => 'Nach Steuern',
|
||||
'color' => 'Farbe',
|
||||
'show' => 'anzeigen',
|
||||
'show' => 'Anzeigen',
|
||||
'empty_columns' => 'Leere Spalten',
|
||||
'project_name' => 'Projektname',
|
||||
'counter_pattern_error' => 'Um :client_counter zu verwenden, fügen Sie bitte entweder :client_number oder :client_id_number hinzu, um Konflikte zu vermeiden',
|
||||
@ -4180,7 +4148,7 @@ https://invoiceninja.github.io/docs/migration/#troubleshooting',
|
||||
'count_days' => ':count Tage',
|
||||
'web_session_timeout' => 'Web-Sitzungs-Timeout',
|
||||
'security_settings' => 'Sicherheitseinstellungen',
|
||||
'resend_email' => 'Bestätigungsemail erneut versenden ',
|
||||
'resend_email' => 'Bestätigungs-E-Mail erneut versenden ',
|
||||
'confirm_your_email_address' => 'Bitte bestätigen Sie Ihre E-Mail-Adresse',
|
||||
'freshbooks' => 'FreshBooks',
|
||||
'invoice2go' => 'Invoice2go',
|
||||
@ -4195,7 +4163,7 @@ https://invoiceninja.github.io/docs/migration/#troubleshooting',
|
||||
'billing_coupon_notice' => 'Ihr Rabatt wird an der Kasse abgezogen.',
|
||||
'use_last_email' => 'Vorherige E-Mail benutzen',
|
||||
'activate_company' => 'Unternehmen aktivieren',
|
||||
'activate_company_help' => 'Aktivieren sie Email, wiederkehrende Rechnungen und Benachrichtigungen',
|
||||
'activate_company_help' => 'E-Mails, wiederkehrende Rechnungen und Benachrichtigungen aktivieren',
|
||||
'an_error_occurred_try_again' => 'Ein Fehler ist aufgetreten, bitte versuchen Sie es erneut.',
|
||||
'please_first_set_a_password' => 'Bitte vergeben Sie zuerst ein Passwort.',
|
||||
'changing_phone_disables_two_factor' => 'Achtung: Das Ändern deiner Telefonnummer wird die Zwei-Faktor-Authentifizierung deaktivieren',
|
||||
@ -4269,7 +4237,7 @@ https://invoiceninja.github.io/docs/migration/#troubleshooting',
|
||||
'user_duplicate_error' => 'Derselbe Benutzer kann nicht derselben Firma hinzugefügt werden',
|
||||
'user_cross_linked_error' => 'Der Benutzer ist vorhanden, kann aber nicht mit mehreren Konten verknüpft werden',
|
||||
'ach_verification_notification_label' => 'ACH-Verifizierung',
|
||||
'ach_verification_notification' => 'Für die Verbindung von Bankkonten ist eine Überprüfung erforderlich. Das Zahlungsgateway sendet zu diesem Zweck automatisch zwei kleine Einzahlungen. Es dauert 1-2 Werktage, bis diese Einzahlungen auf dem Online-Kontoauszug des Kunden erscheinen.',
|
||||
'ach_verification_notification' => 'Für die Verbindung von Bankkonten ist eine Überprüfung erforderlich. Das Zahlungs-Gateway sendet zu diesem Zweck automatisch zwei kleine Einzahlungen. Es dauert 1-2 Werktage, bis diese Einzahlungen auf dem Online-Kontoauszug des Kunden erscheinen.',
|
||||
'login_link_requested_label' => 'Anmeldelink angefordert',
|
||||
'login_link_requested' => 'Es gab eine Aufforderung, sich über einen Link anzumelden. Wenn Sie dies nicht angefordert haben, können Sie es ignorieren.',
|
||||
'invoices_backup_subject' => 'Ihre Rechnungen stehen zum Download bereit',
|
||||
@ -4281,7 +4249,7 @@ https://invoiceninja.github.io/docs/migration/#troubleshooting',
|
||||
'company_import_failure_subject' => 'Fehler beim Importieren von :company',
|
||||
'company_import_failure_body' => 'Beim Importieren der Unternehmensdaten ist ein Fehler aufgetreten, die Fehlermeldung lautete:',
|
||||
'recurring_invoice_due_date' => 'Fälligkeitsdatum',
|
||||
'amount_cents' => 'Betrag in Pfennigen, Pence oder Cents',
|
||||
'amount_cents' => 'Betrag in Pennies, Pence oder Cent, d. h. für $0.10 bitte 10 eingeben',
|
||||
'default_payment_method_label' => 'Standard Zahlungsart',
|
||||
'default_payment_method' => 'Machen Sie dies zu Ihrer bevorzugten Zahlungsmethode',
|
||||
'already_default_payment_method' => 'Dies ist die von Ihnen bevorzugte Art der Bezahlung.',
|
||||
@ -4363,7 +4331,7 @@ https://invoiceninja.github.io/docs/migration/#troubleshooting',
|
||||
'show_pdf_preview_help' => 'PDF-Vorschau bei der Bearbeitung von Rechnungen anzeigen',
|
||||
'print_pdf' => 'PDF drucken',
|
||||
'remind_me' => 'Erinnere mich',
|
||||
'instant_bank_pay' => 'Instant Bank Pay',
|
||||
'instant_bank_pay' => 'Sofortige Banküberweisung',
|
||||
'click_selected' => 'Ausgewähltes anklicken',
|
||||
'hide_preview' => 'Vorschau ausblenden',
|
||||
'edit_record' => 'Datensatz bearbeiten',
|
||||
@ -4380,8 +4348,8 @@ https://invoiceninja.github.io/docs/migration/#troubleshooting',
|
||||
'persist_ui_help' => 'UI-Status lokal speichern, damit die Anwendung an der letzten Position startet (Deaktivierung kann die Leistung verbessern)',
|
||||
'client_postal_code' => 'Postleitzahl des Kunden',
|
||||
'client_vat_number' => 'Umsatzsteuer-Identifikationsnummer des Kunden',
|
||||
'has_tasks' => 'Has Tasks',
|
||||
'registration' => 'Registration',
|
||||
'has_tasks' => 'Hat Aufgaben',
|
||||
'registration' => 'Registrierung',
|
||||
'unauthorized_stripe_warning' => 'Bitte autorisieren Sie Stripe zur Annahme von Online-Zahlungen.',
|
||||
'fpx' => 'FPX',
|
||||
'update_all_records' => 'Alle Datensätze aktualisieren',
|
||||
@ -4389,14 +4357,14 @@ https://invoiceninja.github.io/docs/migration/#troubleshooting',
|
||||
'updated_company' => 'Unternehmen wurde erfolgreich aktualisiert',
|
||||
'kbc' => 'KBC',
|
||||
'why_are_you_leaving' => 'Helfen Sie uns, uns zu verbessern, indem Sie uns sagen, warum (optional)',
|
||||
'webhook_success' => 'Webhook Success',
|
||||
'webhook_success' => 'Webhook erfolgreich',
|
||||
'error_cross_client_tasks' => 'Die Aufgaben müssen alle zum selben Kunden gehören',
|
||||
'error_cross_client_expenses' => 'Die Ausgaben müssen alle zu demselben Kunden gehören',
|
||||
'app' => 'App',
|
||||
'for_best_performance' => 'Für die beste Leistung laden Sie die App herunter :app',
|
||||
'bulk_email_invoice' => 'Email Invoice',
|
||||
'bulk_email_quote' => 'Email Quote',
|
||||
'bulk_email_credit' => 'Email Credit',
|
||||
'bulk_email_invoice' => 'Email Rechnung',
|
||||
'bulk_email_quote' => 'Angebot per E-Mail senden',
|
||||
'bulk_email_credit' => 'Guthaben per E-Mail senden',
|
||||
'removed_recurring_expense' => 'Erfolgreich wiederkehrende Ausgaben entfernt',
|
||||
'search_recurring_expense' => 'Wiederkehrende Ausgaben suchen',
|
||||
'search_recurring_expenses' => 'Wiederkehrende Ausgaben suchen',
|
||||
@ -4404,18 +4372,18 @@ https://invoiceninja.github.io/docs/migration/#troubleshooting',
|
||||
'include_drafts' => 'Entwürfe einschließen',
|
||||
'include_drafts_help' => 'Entwürfe von Aufzeichnungen in Berichte einbeziehen',
|
||||
'is_invoiced' => 'Ist in Rechnung gestellt',
|
||||
'change_plan' => 'Change Plan',
|
||||
'change_plan' => 'Tarif ändern',
|
||||
'persist_data' => 'Daten aufbewahren',
|
||||
'customer_count' => 'Kundenzahl',
|
||||
'verify_customers' => 'Kunden überprüfen',
|
||||
'google_analytics_tracking_id' => 'Google Analytics Tracking ID',
|
||||
'decimal_comma' => 'Decimal Comma',
|
||||
'decimal_comma' => 'Dezimaltrennzeichen',
|
||||
'use_comma_as_decimal_place' => 'Komma als Dezimalstelle in Formularen verwenden',
|
||||
'select_method' => 'Select Method',
|
||||
'select_platform' => 'Select Platform',
|
||||
'select_method' => 'Methode auswählen',
|
||||
'select_platform' => 'Plattform auswählen',
|
||||
'use_web_app_to_connect_gmail' => 'Bitte verwenden Sie die Web-App, um sich mit Gmail zu verbinden',
|
||||
'expense_tax_help' => 'Postensteuersätze sind deaktiviert',
|
||||
'enable_markdown' => 'Enable Markdown',
|
||||
'enable_markdown' => 'Markdown verwenden',
|
||||
'enable_markdown_help' => 'Konvertierung von Markdown in HTML in der PDF-Datei',
|
||||
'add_second_contact' => 'Zweiten Kontakt hinzufügen',
|
||||
'previous_page' => 'Vorherige Seite',
|
||||
@ -4462,36 +4430,36 @@ https://invoiceninja.github.io/docs/migration/#troubleshooting',
|
||||
'include_deleted_clients_help' => 'Datensätze von gelöschten Kunden laden',
|
||||
'step_1_sign_in' => 'Schritt 1: Registrieren',
|
||||
'step_2_authorize' => 'Schritt 2: autorisieren',
|
||||
'account_id' => 'Account ID',
|
||||
'account_id' => 'Konto-ID',
|
||||
'migration_not_yet_completed' => 'Die Migration ist noch nicht abgeschlossen',
|
||||
'show_task_end_date' => 'Ende der Aufgabe anzeigen',
|
||||
'show_task_end_date_help' => 'Aktivieren Sie die Angabe des Enddatums der Aufgabe',
|
||||
'gateway_setup' => 'Gateway-Einstellungen',
|
||||
'preview_sidebar' => 'Vorschau der Seitenleiste',
|
||||
'years_data_shown' => 'Years Data Shown',
|
||||
'years_data_shown' => 'Daten für wie viele Jahre anzeigen?',
|
||||
'ended_all_sessions' => 'alle Sitzungen erfolgreich beendet',
|
||||
'end_all_sessions' => 'Alle Sitzungen beenden',
|
||||
'count_session' => '1 Session',
|
||||
'count_sessions' => ':count Sessions',
|
||||
'count_session' => '1 Sitzung',
|
||||
'count_sessions' => ':count Sitzungen',
|
||||
'invoice_created' => 'Rechnung erstellt',
|
||||
'quote_created' => 'Angebot erstellt',
|
||||
'credit_created' => 'Gutschrift erstellt',
|
||||
'enterprise' => 'Enterprise',
|
||||
'invoice_item' => 'Invoice Item',
|
||||
'quote_item' => 'Quote Item',
|
||||
'order' => 'Order',
|
||||
'search_kanban' => 'Search Kanban',
|
||||
'search_kanbans' => 'Search Kanban',
|
||||
'move_top' => 'Nach oben bewegen',
|
||||
'move_up' => 'Nach unten bewegen',
|
||||
'move_down' => 'Move Down',
|
||||
'move_bottom' => 'Move Bottom',
|
||||
'invoice_item' => 'Rechnungsposition',
|
||||
'quote_item' => 'Angebotsposition',
|
||||
'order' => 'Bestellung',
|
||||
'search_kanban' => 'Kanban auswählen',
|
||||
'search_kanbans' => 'Kanban auswählen',
|
||||
'move_top' => 'Ganz nach oben verschieben',
|
||||
'move_up' => 'Nach oben verschieben',
|
||||
'move_down' => 'Nach unten verschieben',
|
||||
'move_bottom' => 'Ganz nach unten verschieben',
|
||||
'body_variable_missing' => 'Fehler: das benutzerdefinierte E-Mail Template muss die :body Variable beinhalten',
|
||||
'add_body_variable_message' => 'bitte stelle sicher das die :body Variable eingefügt ist',
|
||||
'view_date_formats' => 'View Date Formats',
|
||||
'is_viewed' => 'Is Viewed',
|
||||
'view_date_formats' => 'Zeige Datumsformate',
|
||||
'is_viewed' => 'Ist angesehen',
|
||||
'letter' => 'Letter',
|
||||
'legal' => 'Legal',
|
||||
'legal' => 'Rechtliches',
|
||||
'page_layout' => 'Seiten Layout',
|
||||
'portrait' => 'Hochformat',
|
||||
'landscape' => 'Querformat',
|
||||
@ -4499,31 +4467,31 @@ https://invoiceninja.github.io/docs/migration/#troubleshooting',
|
||||
'upgrade_to_paid_plan' => 'Führen Sie ein Upgrade auf einen kostenpflichtigen Plan durch, um die erweiterten Einstellungen zu aktivieren',
|
||||
'invoice_payment_terms' => 'Zahlungsbedingungen für Rechnungen',
|
||||
'quote_valid_until' => 'Angebot gültig bis',
|
||||
'no_headers' => 'No Headers',
|
||||
'add_header' => 'Add Header',
|
||||
'remove_header' => 'Remove Header',
|
||||
'return_url' => 'Return URL',
|
||||
'rest_method' => 'REST Method',
|
||||
'header_key' => 'Header Key',
|
||||
'header_value' => 'Header Value',
|
||||
'recurring_products' => 'Recurring Products',
|
||||
'promo_discount' => 'Promo Discount',
|
||||
'allow_cancellation' => 'Allow Cancellation',
|
||||
'per_seat_enabled' => 'Per Seat Enabled',
|
||||
'max_seats_limit' => 'Max Seats Limit',
|
||||
'trial_enabled' => 'Trial Enabled',
|
||||
'trial_duration' => 'Trial Duration',
|
||||
'allow_query_overrides' => 'Allow Query Overrides',
|
||||
'allow_plan_changes' => 'Allow Plan Changes',
|
||||
'no_headers' => 'Keine Header',
|
||||
'add_header' => 'Header hinzufügen',
|
||||
'remove_header' => 'Kopfzeile entfernen',
|
||||
'return_url' => 'Return-URL',
|
||||
'rest_method' => 'REST-Methode',
|
||||
'header_key' => 'Header-Key',
|
||||
'header_value' => 'Header-Wert',
|
||||
'recurring_products' => 'Wiederkehrende Produkte',
|
||||
'promo_discount' => 'Promo-Rabatt',
|
||||
'allow_cancellation' => 'Ermögliche Storno',
|
||||
'per_seat_enabled' => 'Pro Platz Aktiviert',
|
||||
'max_seats_limit' => 'Max. Plätze Limit',
|
||||
'trial_enabled' => 'Testversion aktiv',
|
||||
'trial_duration' => 'Testzeitraum',
|
||||
'allow_query_overrides' => 'Überschreiben von Abfragen zulassen',
|
||||
'allow_plan_changes' => 'Planänderungen zulassen',
|
||||
'plan_map' => 'Plan Map',
|
||||
'refund_period' => 'Refund Period',
|
||||
'webhook_configuration' => 'Webhook Configuration',
|
||||
'purchase_page' => 'Purchase Page',
|
||||
'refund_period' => 'Erstattungszeitraum',
|
||||
'webhook_configuration' => 'Webhook-Konfiguration',
|
||||
'purchase_page' => 'Kauf-Seite',
|
||||
'email_bounced' => 'E-Mail zurückgesendet',
|
||||
'email_spam_complaint' => 'Spam Complaint',
|
||||
'email_spam_complaint' => 'Spam-Beschwerde',
|
||||
'email_delivery' => 'E-Mail-Zustellung',
|
||||
'webhook_response' => 'Webhook Response',
|
||||
'pdf_response' => 'PDF Response',
|
||||
'webhook_response' => 'Webhook-Antwort',
|
||||
'pdf_response' => 'PDF-Antwort',
|
||||
'authentication_failure' => 'Authentifizierungsfehler',
|
||||
'pdf_failed' => 'PDF fehgeschlagen',
|
||||
'pdf_success' => 'PDF erfolgreich',
|
||||
@ -4532,7 +4500,7 @@ https://invoiceninja.github.io/docs/migration/#troubleshooting',
|
||||
'html_mode_help' => 'Vorschau von Aktualisierungen schneller, aber weniger genau',
|
||||
'status_color_theme' => 'Status Farbschema',
|
||||
'load_color_theme' => 'lade Farbschema',
|
||||
'lang_Estonian' => 'Estonian',
|
||||
'lang_Estonian' => 'estnisch',
|
||||
'marked_credit_as_paid' => 'Guthaben erfolgreich als bezahlt markiert',
|
||||
'marked_credits_as_paid' => 'Erfolgreich Kredite als bezahlt markiert',
|
||||
'wait_for_loading' => 'Daten werden geladen - bitte warten Sie, bis der Vorgang abgeschlossen ist',
|
||||
@ -4546,7 +4514,69 @@ https://invoiceninja.github.io/docs/migration/#troubleshooting',
|
||||
'activity_123' => ':user löschte wiederkehrende Ausgabe :recurring_expense',
|
||||
'activity_124' => ':user stellte wiederkehrende Ausgabe :recurring_expense wieder her',
|
||||
'fpx' => "FPX",
|
||||
|
||||
'to_view_entity_set_password' => 'Um die :entity zu sehen, müssen Sie ein Passwort festlegen.',
|
||||
'unsubscribe' => 'Deabonnieren',
|
||||
'unsubscribed' => 'Deabonniert',
|
||||
'unsubscribed_text' => 'Du erhältst nun keine Benachrichtigungen für dieses Dokument mehr.',
|
||||
'client_shipping_state' => 'Liefer-Region Kunde',
|
||||
'client_shipping_city' => 'Lieferort Kunde',
|
||||
'client_shipping_postal_code' => 'Liefer-PLZ Kunde',
|
||||
'client_shipping_country' => 'Kunde Lieferung LAND',
|
||||
'load_pdf' => 'PDF laden',
|
||||
'start_free_trial' => 'Kostenlose Testversion starten',
|
||||
'start_free_trial_message' => 'Teste den Pro-Tarif GRATIS für 14 Tage',
|
||||
'due_on_receipt' => 'Fällig bei Erhalt',
|
||||
'is_paid' => 'Ist bezahlt',
|
||||
'age_group_paid' => 'Bezahlt',
|
||||
'id' => 'ID',
|
||||
'convert_to' => 'Umwandeln in',
|
||||
'client_currency' => 'Kundenwährung',
|
||||
'company_currency' => 'Firmenwährung',
|
||||
'custom_emails_disabled_help' => 'Um Spam zu verhindern braucht es ein Upgrade zu einem bezahlten Account um das E-Mail anzupassen.',
|
||||
'upgrade_to_add_company' => 'Upgrade deinen Tarif um weitere Firmen hinzuzufügen',
|
||||
'file_saved_in_downloads_folder' => 'Die Datei wurde im Downloads-Ordner gespeichert',
|
||||
'small' => 'Klein',
|
||||
'quotes_backup_subject' => 'Deine Angebote stehen zum Download bereit',
|
||||
'credits_backup_subject' => 'Deine Guthaben stehen zum Download bereit',
|
||||
'document_download_subject' => 'Deine Dokumente stehen zum Download bereit',
|
||||
'reminder_message' => 'Mahnung für Rechnung :number über :balance',
|
||||
'gmail_credentials_invalid_subject' => 'Senden mit ungültigen GMail-Anmeldedaten',
|
||||
'gmail_credentials_invalid_body' => 'Ihre GMail-Anmeldedaten sind nicht korrekt. Bitte melden Sie sich im Administratorportal an und navigieren Sie zu Einstellungen > Benutzerdetails und trennen Sie Ihr GMail-Konto und verbinden Sie es erneut. Wir werden Ihnen diese Benachrichtigung täglich senden, bis das Problem behoben ist',
|
||||
'notification_invoice_sent' => 'Rechnung :invoice über :amount wurde an den Kunden :client versendet.',
|
||||
'total_columns' => 'Felder insgesamt',
|
||||
'view_task' => 'Aufgabe anzeugen',
|
||||
'cancel_invoice' => 'Abbrechen',
|
||||
'changed_status' => 'Erfolgreich Aufgabenstatus geändert',
|
||||
'change_status' => 'Status ändern',
|
||||
'enable_touch_events' => 'Touchscreen-Modus aktivieren',
|
||||
'enable_touch_events_help' => 'Scrollen durch wischen',
|
||||
'after_saving' => 'Nach dem Speichern',
|
||||
'view_record' => 'Datensatz anzeigen',
|
||||
'enable_email_markdown' => 'Markdown in E-Mails verwenden',
|
||||
'enable_email_markdown_help' => 'Visuellen Markdown-Editor für E-Mails verwenden',
|
||||
'enable_pdf_markdown' => 'Markdown in PDFs verwenden',
|
||||
'json_help' => 'Achtung: JSON-Dateien, die mit v4 der App erstellt wurden, werden nicht unterstützt',
|
||||
'release_notes' => 'Versionshinweise',
|
||||
'upgrade_to_view_reports' => 'Upgrade deinen Tarif um Berichte anzusehen',
|
||||
'started_tasks' => ':value Aufgaben erfolgreich gestartet',
|
||||
'stopped_tasks' => ':value Aufgaben erfolgreich angehalten',
|
||||
'approved_quote' => 'Angebot erfolgreich angenommen',
|
||||
'approved_quotes' => ':value Angebote erfolgreich angenommen',
|
||||
'client_website' => 'Kunden-Website',
|
||||
'invalid_time' => 'Ungültige Zeit',
|
||||
'signed_in_as' => 'Angemeldet als',
|
||||
'total_results' => 'Ergebnisse insgesamt',
|
||||
'restore_company_gateway' => 'Zahlungs-Gateway wiederherstellen',
|
||||
'archive_company_gateway' => 'Zahlungs-Gateway aktivieren',
|
||||
'delete_company_gateway' => 'Zahlungs-Gateway löschen',
|
||||
'exchange_currency' => 'Währung wechseln',
|
||||
'tax_amount1' => 'Steuerhöhe 1',
|
||||
'tax_amount2' => 'Steuerhöhe 2',
|
||||
'tax_amount3' => 'Steuerhöhe 3',
|
||||
'update_project' => 'Projekt aktualisieren',
|
||||
'auto_archive_invoice_cancelled' => 'Auto-Archivieren Stornierte Rechnung',
|
||||
'auto_archive_invoice_cancelled_help' => 'Automatisch Rechnungen archivieren wenn sie storniert werden',
|
||||
|
||||
);
|
||||
|
||||
return $LANG;
|
||||
|
@ -4574,6 +4574,14 @@ $LANG = array(
|
||||
'update_project' => 'Update Project',
|
||||
'auto_archive_invoice_cancelled' => 'Auto Archive Cancelled Invoice',
|
||||
'auto_archive_invoice_cancelled_help' => 'Automatically archive invoices when they are cancelled',
|
||||
'no_invoices_found' => 'No invoices found',
|
||||
'created_record' => 'Successfully created record',
|
||||
'auto_archive_paid_invoices' => 'Auto Archive Paid',
|
||||
'auto_archive_paid_invoices_help' => 'Automatically archive invoices when they are paid.',
|
||||
'auto_archive_cancelled_invoices' => 'Auto Archive Cancelled',
|
||||
'auto_archive_cancelled_invoices_help' => 'Automatically archive invoices when they are cancelled.',
|
||||
'alternate_pdf_viewer' => 'Alternate PDF Viewer',
|
||||
'alternate_pdf_viewer_help' => 'Improve scrolling over the PDF preview [BETA]',
|
||||
|
||||
);
|
||||
|
||||
|
@ -5,66 +5,66 @@
|
||||
|
||||
<p><b>If your logo imported correctly it will display below. If it didn't import, you'll need to reupload your logo</b></p>
|
||||
|
||||
<p><img src="{{ $company->present()->logo() }}"></p>
|
||||
<p><img src="{{ $logo }}"></p>
|
||||
|
||||
@if(isset($company) && $company->clients->count() >=1)
|
||||
<p><b>{{ ctrans('texts.clients') }}:</b> {{ $company->clients->count() }} </p>
|
||||
@if(isset($company))
|
||||
<p><b>{{ ctrans('texts.clients') }}:</b> {{ $client_count }} </p>
|
||||
@endif
|
||||
|
||||
@if(isset($company) && count($company->products) >=1)
|
||||
<p><b>{{ ctrans('texts.products') }}:</b> {{ count($company->products) }} </p>
|
||||
@if(isset($company))
|
||||
<p><b>{{ ctrans('texts.products') }}:</b> {{ $product_count }} </p>
|
||||
@endif
|
||||
|
||||
@if(isset($company) && count($company->invoices) >=1)
|
||||
<p><b>{{ ctrans('texts.invoices') }}:</b> {{ count($company->invoices) }} </p>
|
||||
@if(isset($company))
|
||||
<p><b>{{ ctrans('texts.invoices') }}:</b> {{ $invoice_count }} </p>
|
||||
@endif
|
||||
|
||||
@if(isset($company) && count($company->payments) >=1)
|
||||
<p><b>{{ ctrans('texts.payments') }}:</b> {{ count($company->payments) }} </p>
|
||||
@if(isset($company))
|
||||
<p><b>{{ ctrans('texts.payments') }}:</b> {{ $payment_count }} </p>
|
||||
@endif
|
||||
|
||||
@if(isset($company) && count($company->recurring_invoices) >=1)
|
||||
<p><b>{{ ctrans('texts.recurring_invoices') }}:</b> {{ count($company->recurring_invoices) }} </p>
|
||||
@if(isset($company))
|
||||
<p><b>{{ ctrans('texts.recurring_invoices') }}:</b> {{ $recurring_invoice_count }} </p>
|
||||
@endif
|
||||
|
||||
@if(isset($company) && count($company->quotes) >=1)
|
||||
<p><b>{{ ctrans('texts.quotes') }}:</b> {{ count($company->quotes) }} </p>
|
||||
@if(isset($company))
|
||||
<p><b>{{ ctrans('texts.quotes') }}:</b> {{ $quote_count }} </p>
|
||||
@endif
|
||||
|
||||
@if(isset($company) && count($company->credits) >=1)
|
||||
<p><b>{{ ctrans('texts.credits') }}:</b> {{ count($company->credits) }} </p>
|
||||
@if(isset($company))
|
||||
<p><b>{{ ctrans('texts.credits') }}:</b> {{ $credit_count }} </p>
|
||||
@endif
|
||||
|
||||
@if(isset($company) && count($company->projects) >=1)
|
||||
<p><b>{{ ctrans('texts.projects') }}:</b> {{ count($company->projects) }} </p>
|
||||
@if(isset($company))
|
||||
<p><b>{{ ctrans('texts.projects') }}:</b> {{ $project_count }} </p>
|
||||
@endif
|
||||
|
||||
@if(isset($company) && count($company->tasks) >=1)
|
||||
<p><b>{{ ctrans('texts.tasks') }}:</b> {{ count($company->tasks) }} </p>
|
||||
@if(isset($company))
|
||||
<p><b>{{ ctrans('texts.tasks') }}:</b> {{ $task_count }} </p>
|
||||
@endif
|
||||
|
||||
@if(isset($company) && count($company->vendors) >=1)
|
||||
<p><b>{{ ctrans('texts.vendors') }}:</b> {{ count($company->vendors) }} </p>
|
||||
@if(isset($company))
|
||||
<p><b>{{ ctrans('texts.vendors') }}:</b> {{ $vendor_count }} </p>
|
||||
@endif
|
||||
|
||||
@if(isset($company) && count($company->expenses) >=1)
|
||||
<p><b>{{ ctrans('texts.expenses') }}:</b> {{ count($company->expenses) }} </p>
|
||||
@if(isset($company))
|
||||
<p><b>{{ ctrans('texts.expenses') }}:</b> {{ $expense_count }} </p>
|
||||
@endif
|
||||
|
||||
@if(isset($company) && count($company->company_gateways) >=1)
|
||||
<p><b>{{ ctrans('texts.gateways') }}:</b> {{ count($company->company_gateways) }} </p>
|
||||
@if(isset($company))
|
||||
<p><b>{{ ctrans('texts.gateways') }}:</b> {{ $company_gateway_count }} </p>
|
||||
@endif
|
||||
|
||||
@if(isset($company) && count($company->client_gateway_tokens) >=1)
|
||||
<p><b>{{ ctrans('texts.tokens') }}:</b> {{ count($company->client_gateway_tokens) }} </p>
|
||||
@if(isset($company))
|
||||
<p><b>{{ ctrans('texts.tokens') }}:</b> {{ $client_gateway_token_count }} </p>
|
||||
@endif
|
||||
|
||||
@if(isset($company) && count($company->tax_rates) >=1)
|
||||
<p><b>{{ ctrans('texts.tax_rates') }}:</b> {{ count($company->tax_rates) }} </p>
|
||||
@if(isset($company))
|
||||
<p><b>{{ ctrans('texts.tax_rates') }}:</b> {{ $tax_rate_count }} </p>
|
||||
@endif
|
||||
|
||||
@if(isset($company) && count($company->documents) >=1)
|
||||
<p><b>{{ ctrans('texts.documents') }}:</b> {{ count($company->documents) }} </p>
|
||||
@if(isset($company))
|
||||
<p><b>{{ ctrans('texts.documents') }}:</b> {{ $document_count }} </p>
|
||||
@endif
|
||||
|
||||
@if(isset($check_data))
|
||||
|
@ -19,11 +19,11 @@ Route::group(['middleware' => ['throttle:300,1', 'api_secret_check']], function
|
||||
});
|
||||
|
||||
Route::group(['middleware' => ['throttle:10,1','api_secret_check','email_db']], function () {
|
||||
Route::post('api/v1/login', 'Auth\LoginController@apiLogin')->name('login.submit');
|
||||
Route::post('api/v1/login', 'Auth\LoginController@apiLogin')->name('login.submit')->middleware('throttle:20,1');;
|
||||
Route::post('api/v1/reset_password', 'Auth\ForgotPasswordController@sendResetLinkEmail');
|
||||
});
|
||||
|
||||
Route::group(['middleware' => ['throttle:300,1', 'api_db', 'token_auth', 'locale'], 'prefix' => 'api/v1', 'as' => 'api.'], function () {
|
||||
Route::group(['middleware' => ['throttle:100,1', 'api_db', 'token_auth', 'locale'], 'prefix' => 'api/v1', 'as' => 'api.'], function () {
|
||||
Route::post('check_subdomain', 'SubdomainController@index')->name('check_subdomain');
|
||||
Route::get('ping', 'PingController@index')->name('ping');
|
||||
Route::get('health_check', 'PingController@health')->name('health_check');
|
||||
@ -152,7 +152,7 @@ Route::group(['middleware' => ['throttle:300,1', 'api_db', 'token_auth', 'locale
|
||||
Route::post('recurring_quotes/bulk', 'RecurringQuoteController@bulk')->name('recurring_quotes.bulk');
|
||||
Route::put('recurring_quotes/{recurring_quote}/upload', 'RecurringQuoteController@upload');
|
||||
|
||||
Route::post('refresh', 'Auth\LoginController@refresh');
|
||||
Route::post('refresh', 'Auth\LoginController@refresh')->middleware('throttle:30,1');
|
||||
|
||||
Route::post('reports/clients', 'Reports\ClientReportController');
|
||||
Route::post('reports/contacts', 'Reports\ClientContactReportController');
|
||||
@ -167,6 +167,7 @@ Route::group(['middleware' => ['throttle:300,1', 'api_db', 'token_auth', 'locale
|
||||
Route::post('reports/payments', 'Reports\PaymentReportController');
|
||||
Route::post('reports/products', 'Reports\ProductReportController');
|
||||
Route::post('reports/tasks', 'Reports\TaskReportController');
|
||||
Route::post('reports/profitloss', 'Reports\ProfitAndLossController');
|
||||
|
||||
Route::get('scheduler', 'SchedulerController@index');
|
||||
Route::post('support/messages/send', 'Support\Messages\SendingController');
|
||||
|
@ -8,7 +8,7 @@ Route::get('client/login', 'Auth\ContactLoginController@showLoginForm')->name('c
|
||||
Route::post('client/login', 'Auth\ContactLoginController@login')->name('client.login.submit');
|
||||
|
||||
Route::get('client/register/{company_key?}', 'Auth\ContactRegisterController@showRegisterForm')->name('client.register')->middleware(['domain_db', 'contact_account', 'contact_register','locale']);
|
||||
Route::post('client/register/{company_key?}', 'Auth\ContactRegisterController@register')->middleware(['domain_db', 'contact_account', 'contact_register', 'locale','throttle:10,1']);
|
||||
Route::post('client/register/{company_key?}', 'Auth\ContactRegisterController@register')->middleware(['domain_db', 'contact_account', 'contact_register', 'locale', 'throttle:10,1']);
|
||||
|
||||
Route::get('client/password/reset', 'Auth\ContactForgotPasswordController@showLinkRequestForm')->name('client.password.request')->middleware(['domain_db', 'contact_account','locale']);
|
||||
Route::post('client/password/email', 'Auth\ContactForgotPasswordController@sendResetLinkEmail')->name('client.password.email')->middleware('locale');
|
||||
@ -62,7 +62,7 @@ Route::group(['middleware' => ['auth:contact', 'locale', 'domain_db','check_clie
|
||||
Route::put('profile/{client_contact}/localization', 'ClientPortal\ProfileController@updateClientLocalization')->name('profile.edit_localization');
|
||||
|
||||
Route::get('payment_methods/{payment_method}/verification', 'ClientPortal\PaymentMethodController@verify')->name('payment_methods.verification');
|
||||
Route::post('payment_methods/{payment_method}/verification', 'ClientPortal\PaymentMethodController@processVerification');
|
||||
Route::post('payment_methods/{payment_method}/verification', 'ClientPortal\PaymentMethodController@processVerification')->middleware(['throttle:10,1']);
|
||||
|
||||
Route::get('payment_methods/confirm', 'ClientPortal\PaymentMethodController@store')->name('payment_methods.confirm');
|
||||
|
||||
|
76
tests/Feature/Export/ClientCsvTest.php
Normal file
76
tests/Feature/Export/ClientCsvTest.php
Normal file
@ -0,0 +1,76 @@
|
||||
<?php
|
||||
/**
|
||||
* Invoice Ninja (https://invoiceninja.com).
|
||||
*
|
||||
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||
*
|
||||
* @copyright Copyright (c) 2021. Invoice Ninja LLC (https://invoiceninja.com)
|
||||
*
|
||||
* @license https://opensource.org/licenses/AAL
|
||||
*/
|
||||
namespace Tests\Feature\Export;
|
||||
|
||||
use App\Models\Invoice;
|
||||
use App\Utils\Traits\MakesHash;
|
||||
use Illuminate\Routing\Middleware\ThrottleRequests;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use League\Csv\Writer;
|
||||
use Tests\MockAccountData;
|
||||
use Tests\TestCase;
|
||||
|
||||
/**
|
||||
* @test
|
||||
*/
|
||||
class ClientCsvTest extends TestCase
|
||||
{
|
||||
use MakesHash;
|
||||
use MockAccountData;
|
||||
|
||||
public function setUp() :void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
$this->withoutMiddleware(
|
||||
ThrottleRequests::class
|
||||
);
|
||||
|
||||
$this->makeTestData();
|
||||
|
||||
$this->withoutExceptionHandling();
|
||||
}
|
||||
|
||||
public function testClientExportCsv()
|
||||
{
|
||||
|
||||
$data = [
|
||||
"date_range" => "this_year",
|
||||
"report_keys" => [],
|
||||
];
|
||||
|
||||
$response = $this->withHeaders([
|
||||
'X-API-SECRET' => config('ninja.api_secret'),
|
||||
'X-API-TOKEN' => $this->token,
|
||||
])->post('/api/v1/reports/clients' , $data);
|
||||
|
||||
$response->assertStatus(200);
|
||||
|
||||
}
|
||||
|
||||
public function testContactExportCsv()
|
||||
{
|
||||
|
||||
$data = [
|
||||
"date_range" => "this_year",
|
||||
"report_keys" => [],
|
||||
];
|
||||
|
||||
$response = $this->withHeaders([
|
||||
'X-API-SECRET' => config('ninja.api_secret'),
|
||||
'X-API-TOKEN' => $this->token,
|
||||
])->post('/api/v1/reports/contacts' , $data);
|
||||
|
||||
$response->assertStatus(200);
|
||||
|
||||
}
|
||||
|
||||
}
|
566
tests/Feature/Export/ProfitAndLossReportTest.php
Normal file
566
tests/Feature/Export/ProfitAndLossReportTest.php
Normal file
@ -0,0 +1,566 @@
|
||||
<?php
|
||||
/**
|
||||
* Invoice Ninja (https://invoiceninja.com).
|
||||
*
|
||||
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||
*
|
||||
* @copyright Copyright (c) 2021. Invoice Ninja LLC (https://invoiceninja.com)
|
||||
*
|
||||
* @license https://opensource.org/licenses/AAL
|
||||
*/
|
||||
namespace Tests\Feature\Export;
|
||||
|
||||
use App\DataMapper\ClientSettings;
|
||||
use App\DataMapper\CompanySettings;
|
||||
use App\Factory\ExpenseCategoryFactory;
|
||||
use App\Factory\ExpenseFactory;
|
||||
use App\Factory\InvoiceFactory;
|
||||
use App\Models\Account;
|
||||
use App\Models\Client;
|
||||
use App\Models\ClientContact;
|
||||
use App\Models\Company;
|
||||
use App\Models\Expense;
|
||||
use App\Models\ExpenseCategory;
|
||||
use App\Models\Invoice;
|
||||
use App\Models\User;
|
||||
use App\Services\Report\ProfitLoss;
|
||||
use App\Utils\Traits\MakesHash;
|
||||
use Database\Factories\ClientContactFactory;
|
||||
use Illuminate\Routing\Middleware\ThrottleRequests;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use League\Csv\Writer;
|
||||
use Tests\MockAccountData;
|
||||
use Tests\TestCase;
|
||||
|
||||
/**
|
||||
* @test
|
||||
* @covers App\Services\Report\ProfitLoss
|
||||
*/
|
||||
class ProfitAndLossReportTest extends TestCase
|
||||
{
|
||||
use MakesHash;
|
||||
|
||||
public $faker;
|
||||
|
||||
public function setUp() :void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
$this->faker = \Faker\Factory::create();
|
||||
|
||||
$this->withoutMiddleware(
|
||||
ThrottleRequests::class
|
||||
);
|
||||
|
||||
$this->withoutExceptionHandling();
|
||||
|
||||
}
|
||||
|
||||
public $company;
|
||||
|
||||
public $user;
|
||||
|
||||
public $payload;
|
||||
|
||||
public $account;
|
||||
/**
|
||||
*
|
||||
* start_date - Y-m-d
|
||||
end_date - Y-m-d
|
||||
date_range -
|
||||
all
|
||||
last7
|
||||
last30
|
||||
this_month
|
||||
last_month
|
||||
this_quarter
|
||||
last_quarter
|
||||
this_year
|
||||
custom
|
||||
is_income_billed - true = Invoiced || false = Payments
|
||||
expense_billed - true = Expensed || false = Expenses marked as paid
|
||||
include_tax - true tax_included || false - tax_excluded
|
||||
|
||||
*/
|
||||
|
||||
private function buildData()
|
||||
{
|
||||
|
||||
$this->account = Account::factory()->create([
|
||||
'hosted_client_count' => 1000,
|
||||
'hosted_company_count' => 1000
|
||||
]);
|
||||
|
||||
$this->account->num_users = 3;
|
||||
$this->account->save();
|
||||
|
||||
$this->user = User::factory()->create([
|
||||
'account_id' => $this->account->id,
|
||||
'confirmation_code' => 'xyz123',
|
||||
'email' => $this->faker->unique()->safeEmail,
|
||||
]);
|
||||
|
||||
$settings = CompanySettings::defaults();
|
||||
$settings->client_online_payment_notification = false;
|
||||
$settings->client_manual_payment_notification = false;
|
||||
|
||||
$this->company = Company::factory()->create([
|
||||
'account_id' => $this->account->id,
|
||||
'settings' => $settings
|
||||
]);
|
||||
|
||||
$this->payload = [
|
||||
'start_date' => '2000-01-01',
|
||||
'end_date' => '2030-01-11',
|
||||
'date_range' => 'custom',
|
||||
'is_income_billed' => true,
|
||||
'include_tax' => false
|
||||
];
|
||||
|
||||
}
|
||||
|
||||
public function testProfitLossInstance()
|
||||
{
|
||||
$this->buildData();
|
||||
|
||||
$pl = new ProfitLoss($this->company, $this->payload);
|
||||
|
||||
$this->assertInstanceOf(ProfitLoss::class, $pl);
|
||||
|
||||
$this->account->delete();
|
||||
}
|
||||
|
||||
public function testSimpleInvoiceIncome()
|
||||
{
|
||||
$this->buildData();
|
||||
|
||||
$client = Client::factory()->create([
|
||||
'user_id' => $this->user->id,
|
||||
'company_id' => $this->company->id,
|
||||
'is_deleted' => 0,
|
||||
]);
|
||||
|
||||
Invoice::factory()->count(2)->create([
|
||||
'client_id' => $client->id,
|
||||
'user_id' => $this->user->id,
|
||||
'company_id' => $this->company->id,
|
||||
'amount' => 11,
|
||||
'balance' => 11,
|
||||
'status_id' => 2,
|
||||
'total_taxes' => 1,
|
||||
'date' => '2022-01-01',
|
||||
'terms' => 'nada',
|
||||
'discount' => 0,
|
||||
'tax_rate1' => 0,
|
||||
'tax_rate2' => 0,
|
||||
'tax_rate3' => 0,
|
||||
'tax_name1' => '',
|
||||
'tax_name2' => '',
|
||||
'tax_name3' => '',
|
||||
'uses_inclusive_taxes' => false,
|
||||
]);
|
||||
|
||||
$pl = new ProfitLoss($this->company, $this->payload);
|
||||
$pl->build();
|
||||
|
||||
|
||||
$this->assertEquals(20.0, $pl->getIncome());
|
||||
$this->assertEquals(2, $pl->getIncomeTaxes());
|
||||
|
||||
$this->account->delete();
|
||||
}
|
||||
|
||||
public function testSimpleInvoiceIncomeWithInclusivesTaxes()
|
||||
{
|
||||
$this->buildData();
|
||||
|
||||
$client = Client::factory()->create([
|
||||
'user_id' => $this->user->id,
|
||||
'company_id' => $this->company->id,
|
||||
'is_deleted' => 0,
|
||||
]);
|
||||
|
||||
Invoice::factory()->count(2)->create([
|
||||
'client_id' => $client->id,
|
||||
'user_id' => $this->user->id,
|
||||
'company_id' => $this->company->id,
|
||||
'amount' => 10,
|
||||
'balance' => 10,
|
||||
'status_id' => 2,
|
||||
'total_taxes' => 1,
|
||||
'date' => '2022-01-01',
|
||||
'terms' => 'nada',
|
||||
'discount' => 0,
|
||||
'tax_rate1' => 10,
|
||||
'tax_rate2' => 0,
|
||||
'tax_rate3' => 0,
|
||||
'tax_name1' => "GST",
|
||||
'tax_name2' => '',
|
||||
'tax_name3' => '',
|
||||
'uses_inclusive_taxes' => true,
|
||||
]);
|
||||
|
||||
$pl = new ProfitLoss($this->company, $this->payload);
|
||||
$pl->build();
|
||||
|
||||
|
||||
$this->assertEquals(18.0, $pl->getIncome());
|
||||
$this->assertEquals(2, $pl->getIncomeTaxes());
|
||||
|
||||
$this->account->delete();
|
||||
}
|
||||
|
||||
|
||||
public function testSimpleInvoiceIncomeWithForeignExchange()
|
||||
{
|
||||
$this->buildData();
|
||||
|
||||
$settings = ClientSettings::defaults();
|
||||
$settings->currency_id = "2";
|
||||
|
||||
$client = Client::factory()->create([
|
||||
'user_id' => $this->user->id,
|
||||
'company_id' => $this->company->id,
|
||||
'is_deleted' => 0,
|
||||
'settings' => $settings,
|
||||
]);
|
||||
|
||||
Invoice::factory()->count(2)->create([
|
||||
'client_id' => $client->id,
|
||||
'user_id' => $this->user->id,
|
||||
'company_id' => $this->company->id,
|
||||
'amount' => 10,
|
||||
'balance' => 10,
|
||||
'status_id' => 2,
|
||||
'total_taxes' => 1,
|
||||
'date' => '2022-01-01',
|
||||
'terms' => 'nada',
|
||||
'discount' => 0,
|
||||
'tax_rate1' => 10,
|
||||
'tax_rate2' => 0,
|
||||
'tax_rate3' => 0,
|
||||
'tax_name1' => "GST",
|
||||
'tax_name2' => '',
|
||||
'tax_name3' => '',
|
||||
'uses_inclusive_taxes' => true,
|
||||
'exchange_rate' => 0.5
|
||||
]);
|
||||
|
||||
$pl = new ProfitLoss($this->company, $this->payload);
|
||||
$pl->build();
|
||||
|
||||
$this->assertEquals(36.0, $pl->getIncome());
|
||||
$this->assertEquals(4, $pl->getIncomeTaxes());
|
||||
|
||||
$this->account->delete();
|
||||
}
|
||||
|
||||
|
||||
public function testSimpleInvoicePaymentIncome()
|
||||
{
|
||||
$this->buildData();
|
||||
|
||||
$this->payload = [
|
||||
'start_date' => '2000-01-01',
|
||||
'end_date' => '2030-01-11',
|
||||
'date_range' => 'custom',
|
||||
'is_income_billed' => false,
|
||||
'include_tax' => false
|
||||
];
|
||||
|
||||
|
||||
$settings = ClientSettings::defaults();
|
||||
$settings->currency_id = "1";
|
||||
|
||||
$client = Client::factory()->create([
|
||||
'user_id' => $this->user->id,
|
||||
'company_id' => $this->company->id,
|
||||
'is_deleted' => 0,
|
||||
'settings' => $settings,
|
||||
]);
|
||||
|
||||
$contact = ClientContact::factory()->create([
|
||||
'client_id' => $client->id
|
||||
]);
|
||||
|
||||
$i = Invoice::factory()->create([
|
||||
'client_id' => $client->id,
|
||||
'user_id' => $this->user->id,
|
||||
'company_id' => $this->company->id,
|
||||
'amount' => 10,
|
||||
'balance' => 10,
|
||||
'status_id' => 2,
|
||||
'total_taxes' => 0,
|
||||
'date' => '2022-01-01',
|
||||
'terms' => 'nada',
|
||||
'discount' => 0,
|
||||
'tax_rate1' => 0,
|
||||
'tax_rate2' => 0,
|
||||
'tax_rate3' => 0,
|
||||
'tax_name1' => "",
|
||||
'tax_name2' => '',
|
||||
'tax_name3' => '',
|
||||
'uses_inclusive_taxes' => true,
|
||||
'exchange_rate' => 1
|
||||
]);
|
||||
|
||||
$i->service()->markPaid()->save();
|
||||
|
||||
$pl = new ProfitLoss($this->company, $this->payload);
|
||||
$pl->build();
|
||||
|
||||
$this->assertEquals(10.0, $pl->getIncome());
|
||||
|
||||
$this->account->delete();
|
||||
}
|
||||
|
||||
|
||||
public function testSimpleExpense()
|
||||
{
|
||||
$this->buildData();
|
||||
|
||||
$e = Expense::factory()->create([
|
||||
'amount' => 10,
|
||||
'company_id' => $this->company->id,
|
||||
'user_id' => $this->user->id,
|
||||
'date' => '2022-01-01',
|
||||
]);
|
||||
|
||||
$pl = new ProfitLoss($this->company, $this->payload);
|
||||
$pl->build();
|
||||
|
||||
$expenses = $pl->getExpenses();
|
||||
|
||||
$expense = $expenses[0];
|
||||
|
||||
$this->assertEquals(10, $expense->total);
|
||||
|
||||
$this->account->delete();
|
||||
|
||||
}
|
||||
|
||||
public function testSimpleExpenseAmountTax()
|
||||
{
|
||||
$this->buildData();
|
||||
|
||||
$e = ExpenseFactory::create($this->company->id, $this->user->id);
|
||||
$e->amount = 10;
|
||||
$e->date = '2022-01-01';
|
||||
$e->calculate_tax_by_amount = true;
|
||||
$e->tax_amount1 = 10;
|
||||
$e->save();
|
||||
|
||||
$pl = new ProfitLoss($this->company, $this->payload);
|
||||
$pl->build();
|
||||
|
||||
$expenses = $pl->getExpenses();
|
||||
|
||||
$expense = $expenses[0];
|
||||
|
||||
$this->assertEquals(10, $expense->total);
|
||||
$this->assertEquals(10, $expense->tax);
|
||||
|
||||
$this->account->delete();
|
||||
|
||||
}
|
||||
|
||||
public function testSimpleExpenseTaxRateExclusive()
|
||||
{
|
||||
$this->buildData();
|
||||
|
||||
$e = ExpenseFactory::create($this->company->id, $this->user->id);
|
||||
$e->amount = 10;
|
||||
$e->date = '2022-01-01';
|
||||
$e->tax_rate1 = 10;
|
||||
$e->tax_name1 = 'GST';
|
||||
$e->uses_inclusive_taxes = false;
|
||||
$e->save();
|
||||
|
||||
$pl = new ProfitLoss($this->company, $this->payload);
|
||||
$pl->build();
|
||||
|
||||
$expenses = $pl->getExpenses();
|
||||
|
||||
$expense = $expenses[0];
|
||||
|
||||
$this->assertEquals(10, $expense->total);
|
||||
$this->assertEquals(1, $expense->tax);
|
||||
|
||||
$this->account->delete();
|
||||
|
||||
}
|
||||
|
||||
public function testSimpleExpenseTaxRateInclusive()
|
||||
{
|
||||
$this->buildData();
|
||||
|
||||
$e = ExpenseFactory::create($this->company->id, $this->user->id);
|
||||
$e->amount = 10;
|
||||
$e->date = '2022-01-01';
|
||||
$e->tax_rate1 = 10;
|
||||
$e->tax_name1 = 'GST';
|
||||
$e->uses_inclusive_taxes = false;
|
||||
$e->save();
|
||||
|
||||
$pl = new ProfitLoss($this->company, $this->payload);
|
||||
$pl->build();
|
||||
|
||||
$expenses = $pl->getExpenses();
|
||||
|
||||
$expense = $expenses[0];
|
||||
|
||||
$this->assertEquals(10, $expense->total);
|
||||
$this->assertEquals(1, $expense->tax);
|
||||
|
||||
$this->account->delete();
|
||||
|
||||
}
|
||||
|
||||
|
||||
public function testSimpleExpenseBreakdown()
|
||||
{
|
||||
$this->buildData();
|
||||
|
||||
$e = Expense::factory()->create([
|
||||
'amount' => 10,
|
||||
'company_id' => $this->company->id,
|
||||
'user_id' => $this->user->id,
|
||||
'date' => '2022-01-01',
|
||||
'exchange_rate' => 1,
|
||||
'currency_id' => $this->company->settings->currency_id
|
||||
]);
|
||||
|
||||
$pl = new ProfitLoss($this->company, $this->payload);
|
||||
$pl->build();
|
||||
|
||||
$expenses = $pl->getExpenses();
|
||||
|
||||
$bd = $pl->getExpenseBreakDown();
|
||||
|
||||
$this->assertEquals(array_sum(array_column($bd,'total')), 10);
|
||||
|
||||
$this->account->delete();
|
||||
|
||||
}
|
||||
|
||||
|
||||
public function testSimpleExpenseCategoriesBreakdown()
|
||||
{
|
||||
$this->buildData();
|
||||
|
||||
$ec = ExpenseCategoryFactory::create($this->company->id, $this->user->id);
|
||||
$ec->name = 'Accounting';
|
||||
$ec->save();
|
||||
|
||||
$e = Expense::factory()->create([
|
||||
'category_id' => $ec->id,
|
||||
'amount' => 10,
|
||||
'company_id' => $this->company->id,
|
||||
'user_id' => $this->user->id,
|
||||
'date' => '2022-01-01',
|
||||
'exchange_rate' => 1,
|
||||
'currency_id' => $this->company->settings->currency_id
|
||||
]);
|
||||
|
||||
|
||||
$ec = ExpenseCategoryFactory::create($this->company->id, $this->user->id);
|
||||
$ec->name = 'Fuel';
|
||||
$ec->save();
|
||||
|
||||
$e = Expense::factory(2)->create([
|
||||
'category_id' => $ec->id,
|
||||
'amount' => 10,
|
||||
'company_id' => $this->company->id,
|
||||
'user_id' => $this->user->id,
|
||||
'date' => '2022-01-01',
|
||||
'exchange_rate' => 1,
|
||||
'currency_id' => $this->company->settings->currency_id
|
||||
]);
|
||||
|
||||
|
||||
$pl = new ProfitLoss($this->company, $this->payload);
|
||||
$pl->build();
|
||||
|
||||
$expenses = $pl->getExpenses();
|
||||
|
||||
$bd = $pl->getExpenseBreakDown();
|
||||
|
||||
$this->assertEquals(array_sum(array_column($bd,'total')), 30);
|
||||
|
||||
$this->account->delete();
|
||||
|
||||
}
|
||||
|
||||
|
||||
public function testCsvGeneration()
|
||||
{
|
||||
$this->buildData();
|
||||
|
||||
$client = Client::factory()->create([
|
||||
'user_id' => $this->user->id,
|
||||
'company_id' => $this->company->id,
|
||||
'is_deleted' => 0,
|
||||
]);
|
||||
|
||||
Invoice::factory()->count(1)->create([
|
||||
'client_id' => $client->id,
|
||||
'user_id' => $this->user->id,
|
||||
'company_id' => $this->company->id,
|
||||
'amount' => 10,
|
||||
'balance' => 10,
|
||||
'status_id' => 2,
|
||||
'total_taxes' => 1,
|
||||
'date' => '2022-01-01',
|
||||
'terms' => 'nada',
|
||||
'discount' => 0,
|
||||
'tax_rate1' => 10,
|
||||
'tax_rate2' => 0,
|
||||
'tax_rate3' => 0,
|
||||
'tax_name1' => "GST",
|
||||
'tax_name2' => '',
|
||||
'tax_name3' => '',
|
||||
'uses_inclusive_taxes' => true,
|
||||
]);
|
||||
|
||||
$ec = ExpenseCategoryFactory::create($this->company->id, $this->user->id);
|
||||
$ec->name = 'Accounting';
|
||||
$ec->save();
|
||||
|
||||
$e = Expense::factory()->create([
|
||||
'category_id' => $ec->id,
|
||||
'amount' => 10,
|
||||
'company_id' => $this->company->id,
|
||||
'user_id' => $this->user->id,
|
||||
'date' => '2022-01-01',
|
||||
'exchange_rate' => 1,
|
||||
'currency_id' => $this->company->settings->currency_id
|
||||
]);
|
||||
|
||||
|
||||
$ec = ExpenseCategoryFactory::create($this->company->id, $this->user->id);
|
||||
$ec->name = 'Fuel';
|
||||
$ec->save();
|
||||
|
||||
$e = Expense::factory(2)->create([
|
||||
'category_id' => $ec->id,
|
||||
'amount' => 10,
|
||||
'company_id' => $this->company->id,
|
||||
'user_id' => $this->user->id,
|
||||
'date' => '2022-01-01',
|
||||
'exchange_rate' => 1,
|
||||
'currency_id' => $this->company->settings->currency_id
|
||||
]);
|
||||
|
||||
|
||||
$pl = new ProfitLoss($this->company, $this->payload);
|
||||
$pl->build();
|
||||
|
||||
echo($pl->getCsv());
|
||||
|
||||
$this->assertNotNull($pl->getCsv());
|
||||
|
||||
$this->account->delete();
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,81 @@
|
||||
<?php
|
||||
/**
|
||||
* Invoice Ninja (https://invoiceninja.com).
|
||||
*
|
||||
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||
*
|
||||
* @copyright Copyright (c) 2021. Invoice Ninja LLC (https://invoiceninja.com)
|
||||
*
|
||||
* @license https://opensource.org/licenses/AAL
|
||||
*/
|
||||
namespace Tests\Unit\ValidationRules;
|
||||
|
||||
use App\Http\Requests\Invoice\StoreInvoiceRequest;
|
||||
use App\Http\ValidationRules\Account\BlackListRule;
|
||||
use App\Models\Invoice;
|
||||
use App\Utils\Traits\MakesHash;
|
||||
use Illuminate\Foundation\Testing\DatabaseTransactions;
|
||||
use Illuminate\Support\Facades\Validator;
|
||||
use Tests\MockAccountData;
|
||||
use Tests\TestCase;
|
||||
|
||||
/**
|
||||
* @test
|
||||
*/
|
||||
class UniqueInvoiceNumberValidationTest extends TestCase
|
||||
{
|
||||
|
||||
use MakesHash;
|
||||
use MockAccountData;
|
||||
|
||||
public function setUp() :void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
$this->withoutMiddleware(
|
||||
ThrottleRequests::class
|
||||
);
|
||||
|
||||
$this->makeTestData();
|
||||
|
||||
$this->withoutExceptionHandling();
|
||||
|
||||
}
|
||||
|
||||
public function testValidEmailRule()
|
||||
{
|
||||
auth()->login($this->user);
|
||||
auth()->user()->setCompany($this->company);
|
||||
|
||||
Invoice::factory()->create([
|
||||
'client_id' => $this->client->id,
|
||||
'user_id' => $this->user->id,
|
||||
'company_id' => $this->company->id,
|
||||
'paid_to_date' => 100,
|
||||
'status_id' => 4,
|
||||
'date' => now(),
|
||||
'due_date'=> now(),
|
||||
'number' => 'db_record'
|
||||
]);
|
||||
|
||||
$data = [
|
||||
'client_id' => $this->client->hashed_id,
|
||||
'paid_to_date' => 100,
|
||||
'status_id' => 4,
|
||||
'date' => now(),
|
||||
'due_date'=> now(),
|
||||
'number' => 'db_record'
|
||||
];
|
||||
|
||||
$rules = (new StoreInvoiceRequest())->rules();
|
||||
|
||||
$validator = Validator::make($data, $rules);
|
||||
|
||||
$this->assertFalse($validator->passes());
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user