latest merge

This commit is contained in:
David Bomba 2023-08-06 11:20:15 +10:00
commit 3efff86066
564 changed files with 400227 additions and 393546 deletions

View File

@ -4,6 +4,7 @@ APP_KEY=base64:RR++yx2rJ9kdxbdh3+AmbHLDQu+Q76i++co9Y8ybbno=
APP_DEBUG=false
APP_URL=http://localhost
REACT_URL=http://localhost:3001
DB_CONNECTION=mysql
MULTI_DB_ENABLED=false
@ -33,8 +34,8 @@ MAIL_PORT=2525
MAIL_USERNAME=null
MAIL_PASSWORD=null
MAIL_ENCRYPTION=null
MAIL_FROM_ADDRESS='user@example.com'
MAIL_FROM_NAME='Self Hosted User'
MAIL_FROM_ADDRESS="user@example.com"
MAIL_FROM_NAME="Self Hosted User"
POSTMARK_API_TOKEN=
REQUIRE_HTTPS=false
@ -67,4 +68,4 @@ MICROSOFT_REDIRECT_URI=
APPLE_CLIENT_ID=
APPLE_CLIENT_SECRET=
APPLE_REDIRECT_URI=
APPLE_REDIRECT_URI=

View File

@ -46,7 +46,9 @@ jobs:
git checkout main
npm i
npm run build
cp -r dist/react/* ../public/react
cp -r dist/react/* ../public/react
mkdir -p ../public/tinymce_6.4.2/tinymce/js/
cp -r node_modules/tinymce ../public/tinymce_6.4.2/tinymce/js/
cd ..
rm -rf ui
php artisan ninja:react

View File

@ -1 +1 @@
5.6.5
5.6.25

View File

@ -17,7 +17,7 @@ class EncryptedCast implements CastsAttributes
{
public function get($model, string $key, $value, array $attributes)
{
return strlen($value) > 1 ? decrypt($value) : null;
return is_string($value) && strlen($value) > 1 ? decrypt($value) : null;
}
public function set($model, string $key, $value, array $attributes)

View File

@ -154,7 +154,7 @@ class CheckData extends Command
->subject('Check-Data: '.strtoupper($this->isValid ? Account::RESULT_SUCCESS : Account::RESULT_FAILURE)." [{$database}]");
});
} elseif (! $this->isValid) {
new Exception("Check data failed!!\n".$this->log);
new \Exception("Check data failed!!".$this->log);
}
}

View File

@ -711,6 +711,29 @@ class CreateSingleAccount extends Command
$cg->save();
}
if (config('ninja.testvars.paypal_rest') && ($this->gateway == 'all' || $this->gateway == 'paypal_rest')) {
$cg = new CompanyGateway;
$cg->company_id = $company->id;
$cg->user_id = $user->id;
$cg->gateway_key = '80af24a6a691230bbec33e930ab40665';
$cg->require_cvv = true;
$cg->require_billing_address = true;
$cg->require_shipping_address = true;
$cg->update_details = true;
$cg->config = encrypt(config('ninja.testvars.paypal_rest'));
$cg->save();
// $gateway_types = $cg->driver()->gatewayTypes();
$fees_and_limits = new stdClass;
$fees_and_limits->{3} = new FeesAndLimits;
$cg->fees_and_limits = $fees_and_limits;
$cg->save();
}
if (config('ninja.testvars.checkout') && ($this->gateway == 'all' || $this->gateway == 'checkout')) {
$cg = new CompanyGateway;
$cg->company_id = $company->id;

View File

@ -64,8 +64,6 @@ class ImportMigrations extends Command
*/
public function __construct()
{
$this->faker = Factory::create();
parent::__construct();
}
@ -76,6 +74,8 @@ class ImportMigrations extends Command
*/
public function handle()
{
$this->faker = Factory::create();
$this->buildCache();
$path = $this->option('path') ?? public_path('storage/migrations/import');
@ -105,7 +105,7 @@ class ImportMigrations extends Command
$import_file = public_path("storage/migrations/$filename/migration.json");
Import::dispatch($import_file, $this->getUser()->companies()->first(), $this->getUser());
// StartMigration::dispatch($file->getRealPath(), $this->getUser(), $this->getUser()->companies()->first());
} catch (NonExistingMigrationFile | ProcessingMigrationArchiveFailed | ResourceNotAvailableForMigration | MigrationValidatorFailed | ResourceDependencyMissing $e) {
\Mail::to($user)->send(new MigrationFailed($e, $company));

View File

@ -93,17 +93,6 @@ class MobileLocalization extends Command
$text = str_replace(['<i>', '</i>'], '', $text);
$text = str_replace(['<strong>', '</strong>'], '', $text);
//replace the three lines above with this
// if($language->locale == 'ar') {
// $text = str_replace('\n', " ", $text);
// }
// $text = str_replace(['<strong>', '</strong>','<i>', '</i>','<b>', '</b>'], '', $text);
// $text = str_replace('"', "'", $text);
echo "'$key': '$text',\n";
}

View File

@ -79,6 +79,7 @@ class OpenApiYaml extends Command
Storage::disk('base')->append('/openapi/api-docs.yaml', file_get_contents($path.'/components.yaml'));
Storage::disk('base')->append('/openapi/api-docs.yaml', file_get_contents($path.'/components/responses.yaml'));
Storage::disk('base')->append('/openapi/api-docs.yaml', file_get_contents($path.'/components/examples.yaml'));
$directory = new DirectoryIterator($path . '/components/responses/');

View File

@ -51,6 +51,7 @@ class TranslationsExport extends Command
'fi',
'fr',
'fr_CA',
'fr_CH',
'he',
'hr',
'hu',
@ -133,11 +134,9 @@ class TranslationsExport extends Command
Storage::disk('local')->makeDirectory('lang');
foreach ($this->langs as $lang) {
nlog($lang);
Storage::disk('local')->makeDirectory("lang/{$lang}");
$translations = Lang::getLoader()->load($lang, 'texts');
nlog($translations);
Storage::disk('local')->put("lang/{$lang}/{$lang}.json", json_encode(Arr::dot($translations), JSON_UNESCAPED_UNICODE));
}
}

View File

@ -37,7 +37,6 @@ class AccountCreated extends GenericCounter
*
* date("Y-m-d H:i:s")
*
* @var \DateTime
*/
public $datetime;

View File

@ -37,7 +37,6 @@ class AccountDeleted extends GenericCounter
*
* date("Y-m-d H:i:s")
*
* @var \DateTime
*/
public $datetime;

View File

@ -37,7 +37,6 @@ class AccountPlatform extends GenericMixedMetric
*
* date("Y-m-d H:i:s")
*
* @var \DateTime
*/
public $datetime;

View File

@ -37,7 +37,6 @@ class AccountSignup extends GenericMixedMetric
*
* date("Y-m-d H:i:s")
*
* @var \DateTime
*/
public $datetime;
@ -61,7 +60,7 @@ class AccountSignup extends GenericMixedMetric
* The counter
* set to 1.
*
* @var string
* @var int
*/
public $int_metric1 = 1;

View File

@ -37,7 +37,6 @@ class BankAccountsCreated extends GenericMixedMetric
*
* date("Y-m-d H:i:s")
*
* @var \DateTime
*/
public $datetime;

View File

@ -37,7 +37,6 @@ class DbQuery extends GenericMixedMetric
*
* date("Y-m-d H:i:s")
*
* @var \DateTime
*/
public $datetime;
@ -57,7 +56,7 @@ class DbQuery extends GenericMixedMetric
* The counter
* set to 1.
*
* @var string
* @var int
*/
public $int_metric1 = 1;

View File

@ -37,7 +37,6 @@ class EmailCount extends GenericMixedMetric
*
* date("Y-m-d H:i:s")
*
* @var \DateTime
*/
public $datetime;

View File

@ -37,7 +37,6 @@ class EmailFailure extends GenericMixedMetric
*
* date("Y-m-d H:i:s")
*
* @var \DateTime
*/
public $datetime;
@ -61,7 +60,6 @@ class EmailFailure extends GenericMixedMetric
* The counter
* set to 1.
*
* @var string
*/
public $int_metric1 = 1;

View File

@ -37,7 +37,6 @@ class EmailInvoiceFailure extends GenericMixedMetric
*
* date("Y-m-d H:i:s")
*
* @var \DateTime
*/
public $datetime;

View File

@ -37,7 +37,6 @@ class EmailSuccess extends GenericMixedMetric
*
* date("Y-m-d H:i:s")
*
* @var \DateTime
*/
public $datetime;
@ -61,7 +60,6 @@ class EmailSuccess extends GenericMixedMetric
* The counter
* set to 1.
*
* @var string
*/
public $int_metric1 = 1;

View File

@ -37,7 +37,6 @@ class LivePreview extends GenericCounter
*
* date("Y-m-d H:i:s")
*
* @var \DateTime
*/
public $datetime;

View File

@ -37,7 +37,6 @@ class LoginFailure extends GenericCounter
*
* date("Y-m-d H:i:s")
*
* @var \DateTime
*/
public $datetime;

View File

@ -37,7 +37,6 @@ class LoginSuccess extends GenericCounter
*
* date("Y-m-d H:i:s")
*
* @var \DateTime
*/
public $datetime;

View File

@ -37,7 +37,6 @@ class EmailBounce extends GenericMixedMetric
*
* date("Y-m-d H:i:s")
*
* @var \DateTime
*/
public $datetime;
@ -67,7 +66,6 @@ class EmailBounce extends GenericMixedMetric
* The counter
* set to 1.
*
* @var string
*/
public $int_metric1 = 1;

View File

@ -16,13 +16,13 @@ namespace App\DataMapper;
*/
class BaseSettings
{
//@deprecated
public function __construct($obj)
{
// foreach ($obj as $key => $value) {
// $obj->{$key} = $value;
// }
}
// //@deprecated
// public function __construct($obj)
// {
// // foreach ($obj as $key => $value) {
// // $obj->{$key} = $value;
// // }
// }
public static function setCasts($obj, $casts)
{

View File

@ -47,17 +47,17 @@ class ClientSettings extends BaseSettings
'send_reminders' => 'bool',
];
/**
* Cast object values and return entire class
* prevents missing properties from not being returned
* and always ensure an up to date class is returned.
*
* @param $obj
*/
public function __construct($obj)
{
parent::__construct($obj);
}
// /**
// * Cast object values and return entire class
// * prevents missing properties from not being returned
// * and always ensure an up to date class is returned.
// *
// * @param $obj
// */
// public function __construct($obj)
// {
// // parent::__construct($obj);
// }
/**
* Default Client Settings scaffold.
@ -78,8 +78,8 @@ class ClientSettings extends BaseSettings
/**
* Merges settings from Company to Client.
*
* @param stdClass $company_settings
* @param stdClass $client_settings
* @param $company_settings
* @param $client_settings
* @return stdClass of merged settings
*/
public static function buildClientSettings($company_settings, $client_settings)

View File

@ -767,18 +767,18 @@ class CompanySettings extends BaseSettings
'purchase_order_design_id',
];
/**
* Cast object values and return entire class
* prevents missing properties from not being returned
* and always ensure an up to date class is returned.
*
* @param $obj
* @deprecated
*/
public function __construct()
{
// parent::__construct($obj);
}
// /**
// * Cast object values and return entire class
// * prevents missing properties from not being returned
// * and always ensure an up to date class is returned.
// *
// * @param $obj
// * @deprecated
// */
// public function __construct()
// {
// // parent::__construct($obj);
// }
/**
* Provides class defaults on init.

View File

@ -34,13 +34,4 @@ class DefaultSettings extends BaseSettings
];
}
/**
* @return stdClass
*/
private static function userSettingsObject() : stdClass
{
return (object) [
// 'per_page' => self::$per_page,
];
}
}
}

View File

@ -24,92 +24,78 @@ class EmailTemplateDefaults
case 'email_template_invoice':
return self::emailInvoiceTemplate();
break;
case 'email_template_quote':
return self::emailQuoteTemplate();
break;
case 'email_template_credit':
return self::emailCreditTemplate();
break;
case 'email_template_payment':
return self::emailPaymentTemplate();
break;
case 'email_template_payment_partial':
return self::emailPaymentPartialTemplate();
break;
case 'email_template_statement':
return self::emailStatementTemplate();
break;
case 'email_template_reminder1':
return self::emailReminder1Template();
break;
case 'email_template_reminder2':
return self::emailReminder2Template();
break;
case 'email_template_reminder3':
return self::emailReminder3Template();
break;
case 'email_template_reminder_endless':
return self::emailReminderEndlessTemplate();
break;
case 'email_template_custom1':
return self::emailInvoiceTemplate();
break;
case 'email_template_custom2':
return self::emailInvoiceTemplate();
break;
case 'email_template_custom3':
return self::emailInvoiceTemplate();
case 'email_template_purchase_order':
return self::emailPurchaseOrderTemplate();
break;
/* Subject */
case 'email_subject_purchase_order':
return self::emailPurchaseOrderSubject();
case 'email_subject_invoice':
return self::emailInvoiceSubject();
break;
case 'email_subject_quote':
return self::emailQuoteSubject();
break;
case 'email_subject_credit':
return self::emailCreditSubject();
break;
case 'email_subject_payment':
return self::emailPaymentSubject();
break;
case 'email_subject_payment_partial':
return self::emailPaymentPartialSubject();
break;
case 'email_subject_statement':
return self::emailStatementSubject();
break;
case 'email_subject_reminder1':
return self::emailReminder1Subject();
break;
case 'email_subject_reminder2':
return self::emailReminder2Subject();
break;
case 'email_subject_reminder3':
return self::emailReminder3Subject();
break;
case 'email_subject_reminder_endless':
return self::emailReminderEndlessSubject();
break;
case 'email_subject_custom1':
return self::emailInvoiceSubject();
break;
case 'email_subject_custom2':
return self::emailInvoiceSubject();
break;
case 'email_subject_custom3':
return self::emailInvoiceSubject();
break;
default:
return self::emailInvoiceTemplate();
break;
}
}

View File

@ -141,7 +141,6 @@ class FreeCompanySettings extends BaseSettings
public static $casts = [
'portal_design_id' => 'string',
'currency_id' => 'string',
'task_number_pattern' => 'string',
'task_number_counter' => 'int',
'expense_number_pattern' => 'string',
@ -191,16 +190,16 @@ class FreeCompanySettings extends BaseSettings
'website' => 'string',
];
/**
* Cast object values and return entire class
* prevents missing properties from not being returned
* and always ensure an up to date class is returned.
*
* @param $obj
*/
public function __construct($obj)
{
}
// /**
// * Cast object values and return entire class
// * prevents missing properties from not being returned
// * and always ensure an up to date class is returned.
// *
// * @param $obj
// */
// public function __construct($obj)
// {
// }
/**
* Provides class defaults on init.
@ -223,7 +222,7 @@ class FreeCompanySettings extends BaseSettings
$data->date_format_id = (string) config('ninja.i18n.date_format_id');
$data->country_id = (string) config('ninja.i18n.country_id');
$data->translations = (object) [];
$data->pdf_variables = (object) self::getEntityVariableDefaults();
// $data->pdf_variables = (object) self::getEntityVariableDefaults();
return self::setCasts($data, self::$casts);
}

View File

@ -223,9 +223,12 @@ class Rule extends BaseRule implements RuleInterface
public function calculateRates(): self
{
if ($this->client->is_tax_exempt) {
// nlog("tax exempt");
$this->tax_rate = 0;
$this->reduced_tax_rate = 0;
return $this;
}
// } elseif($this->client_subregion != $this->client->company->tax_data->seller_subregion && in_array($this->client_subregion, $this->eu_country_codes) && $this->client->has_valid_vat_number && $this->eu_business_tax_exempt) {
// nlog("euro zone and tax exempt");
// $this->tax_rate = 0;
@ -246,10 +249,9 @@ class Rule extends BaseRule implements RuleInterface
// $this->tax_rate = $this->client->company->tax_data->regions->EU->subregions->{$this->client->company->country()->iso_3166_2}->tax_rate;
// $this->reduced_tax_rate = $this->client->company->tax_data->regions->EU->subregions->{$this->client->company->country()->iso_3166_2}->reduced_tax_rate;
// }
} else {
$this->tax_rate = $this->client->company->tax_data->regions->AU->subregions->{$this->client->company->country()->iso_3166_2}->tax_rate;
$this->reduced_tax_rate = $this->client->company->tax_data->regions->AU->subregions->{$this->client->company->country()->iso_3166_2}->reduced_tax_rate;
}
$this->tax_rate = $this->client->company->tax_data->regions->AU->subregions->{$this->client->company->country()->iso_3166_2}->tax_rate;
$this->reduced_tax_rate = $this->client->company->tax_data->regions->AU->subregions->{$this->client->company->country()->iso_3166_2}->tax_rate;
return $this;

View File

@ -197,7 +197,7 @@ class BaseRule implements RuleInterface
}
/** If we are in a Origin based state, force the company tax here */
if($company->origin_tax_data?->originDestination == 'O' && ($company->tax_data?->seller_subregion == $this->client_subregion)) {
if($company->origin_tax_data->originDestination == 'O' && ($company->tax_data?->seller_subregion == $this->client_subregion)) {
$tax_data = $company->origin_tax_data;
@ -235,7 +235,7 @@ class BaseRule implements RuleInterface
$this->client_region = $this->region_codes[$this->client->country->iso_3166_2];
match($this->client_region){
'US' => $this->client_subregion = strlen($this->invoice?->client?->tax_data?->geoState) > 1 ? $this->invoice->client->tax_data->geoState : $this->getUSState(),
'US' => $this->client_subregion = isset($this->invoice?->client?->tax_data?->geoState) ? $this->invoice->client->tax_data->geoState : $this->getUSState(),
'EU' => $this->client_subregion = $this->client->country->iso_3166_2,
'AU' => $this->client_subregion = 'AU',
default => $this->client_subregion = $this->client->country->iso_3166_2,

View File

@ -33859,8 +33859,6 @@ class USStates
'99926' => 'AK',
'99927' => 'AK',
'99929' => 'AK',
'13021' => 'NY',
'13024' => 'NY',
];
public static function get(): array

View File

@ -30,7 +30,7 @@ class DesignWasCreated
/**
* Get the channels the event should broadcast on.
*
* @return PrivateChannel
* @return PrivateChannel|array
*/
public function broadcastOn()
{

View File

@ -30,7 +30,7 @@ class DesignWasDeleted
/**
* Get the channels the event should broadcast on.
*
* @return PrivateChannel
* @return PrivateChannel|array
*/
public function broadcastOn()
{

View File

@ -30,7 +30,7 @@ class DesignWasRestored
/**
* Get the channels the event should broadcast on.
*
* @return PrivateChannel
* @return PrivateChannel|array
*/
public function broadcastOn()
{

View File

@ -30,7 +30,7 @@ class DesignWasUpdated
/**
* Get the channels the event should broadcast on.
*
* @return PrivateChannel
* @return PrivateChannel|array
*/
public function broadcastOn()
{

View File

@ -17,8 +17,10 @@ use App\Utils\Ninja;
use Sentry\State\Scope;
use Illuminate\Support\Arr;
use Illuminate\Http\Request;
use InvalidArgumentException;
use Sentry\Laravel\Integration;
use Illuminate\Support\Facades\Schema;
use Aws\Exception\CredentialsException;
use GuzzleHttp\Exception\ConnectException;
use Illuminate\Auth\AuthenticationException;
use League\Flysystem\UnableToCreateDirectory;
@ -34,7 +36,6 @@ use Symfony\Component\Console\Exception\CommandNotFoundException;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use Symfony\Component\HttpKernel\Exception\MethodNotAllowedHttpException;
use Illuminate\Database\Eloquent\ModelNotFoundException as ModelNotFoundException;
use InvalidArgumentException;
class Handler extends ExceptionHandler
{
@ -64,7 +65,7 @@ class Handler extends ExceptionHandler
ConnectException::class,
RuntimeException::class,
InvalidArgumentException::class,
Aws\Exception\CredentialsException::class,
CredentialsException::class,
];
protected $hostedDontReport = [

View File

@ -14,7 +14,7 @@ namespace App\Exceptions;
use Exception;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
use Illuminate\Http\JsonResponse;
class PaymentRefundFailed extends Exception
{
@ -32,14 +32,14 @@ class PaymentRefundFailed extends Exception
* Render the exception into an HTTP response.
*
* @param Request $request
* @return Response
* @return JsonResponse
*/
public function render($request)
{
// $msg = 'Unable to refund the transaction';
$msg = ctrans('texts.warning_local_refund');
if ($this->getMessage() && strlen($this->getMessage()) >= 1) {
if ($this->getMessage() && strlen($this->getMessage()) > 1) {
$msg = $this->getMessage();
}

View File

@ -14,7 +14,7 @@ namespace App\Exceptions;
use Exception;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
use Illuminate\Http\JsonResponse;
class QuoteConversion extends Exception
{
@ -32,7 +32,7 @@ class QuoteConversion extends Exception
* Render the exception into an HTTP response.
*
* @param Request $request
* @return Response
* @return JsonResponse
*/
public function render($request)
{

View File

@ -14,7 +14,7 @@ namespace App\Exceptions;
use Exception;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
use Illuminate\Http\JsonResponse;
class YodleeApiException extends Exception
{
@ -32,14 +32,14 @@ class YodleeApiException extends Exception
* Render the exception into an HTTP response.
*
* @param Request $request
* @return Response
* @return JsonResponse
*/
public function render($request)
{
// $msg = 'Unable to refund the transaction';
$msg = ctrans('texts.error');
if ($this->getMessage() && strlen($this->getMessage()) >= 1) {
if ($this->getMessage() && strlen($this->getMessage()) > 1) {
$msg = $this->getMessage();
}

View File

@ -24,8 +24,7 @@ use App\Transformers\ActivityTransformer;
class ActivityExport extends BaseExport
{
private Company $company;
private $entity_transformer;
public string $date_key = 'created_at';

View File

@ -11,16 +11,26 @@
namespace App\Export\CSV;
use App\Utils\Number;
use App\Models\Client;
use App\Models\Company;
use App\Models\Expense;
use App\Models\Invoice;
use App\Models\Payment;
use League\Fractal\Manager;
use Illuminate\Support\Carbon;
use App\Utils\Traits\MakesHash;
use App\Transformers\TaskTransformer;
use App\Transformers\PaymentTransformer;
use Illuminate\Database\Eloquent\Builder;
use League\Fractal\Serializer\ArraySerializer;
class BaseExport
{
use MakesHash;
public Company $company;
public array $input;
public string $date_key = '';
@ -35,6 +45,312 @@ class BaseExport
public array $forced_keys = [];
protected array $vendor_report_keys = [
'address1' => 'vendor.address1',
'address2' => 'vendor.address2',
'city' => 'vendor.city',
'country' => 'vendor.country_id',
'custom_value1' => 'vendor.custom_value1',
'custom_value2' => 'vendor.custom_value2',
'custom_value3' => 'vendor.custom_value3',
'custom_value4' => 'vendor.custom_value4',
'id_number' => 'vendor.id_number',
'name' => 'vendor.name',
'number' => 'vendor.number',
'client_phone' => 'vendor.phone',
'postal_code' => 'vendor.postal_code',
'private_notes' => 'vendor.private_notes',
'public_notes' => 'vendor.public_notes',
'state' => 'vendor.state',
'vat_number' => 'vendor.vat_number',
'website' => 'vendor.website',
'currency' => 'vendor.currency',
'first_name' => 'vendor_contact.first_name',
'last_name' => 'vendor_contact.last_name',
'contact_phone' => 'vendor_contact.phone',
'contact_custom_value1' => 'vendor_contact.custom_value1',
'contact_custom_value2' => 'vendor_contact.custom_value2',
'contact_custom_value3' => 'vendor_contact.custom_value3',
'contact_custom_value4' => 'vendor_contact.custom_value4',
'email' => 'vendor_contact.email',
'status' => 'vendor.status',
];
protected array $client_report_keys = [
"name" => "client.name",
"user" => "client.user",
"assigned_user" => "client.assigned_user",
"balance" => "client.balance",
"paid_to_date" => "client.paid_to_date",
"currency" => "client.currency_id",
"website" => "client.website",
"private_notes" => "client.private_notes",
"industry" => "client.industry_id",
"size" => "client.size_id",
"work_phone" => "client.phone",
"address1" => "client.address1",
"address2" => "client.address2",
"city" => "client.city",
"state" => "client.state",
"postal_code" => "client.postal_code",
"country" => "client.country_id",
"custom_value4" => "contact.custom_value4",
"shipping_address1" => "client.shipping_address1",
"shipping_address2" => "client.shipping_address2",
"shipping_city" => "client.shipping_city",
"shipping_state" => "client.shipping_state",
"shipping_postal_code" => "client.shipping_postal_code",
"shipping_country" => "client.shipping_country_id",
"payment_terms" => "client.payment_terms",
"vat_number" => "client.vat_number",
"id_number" => "client.id_number",
"public_notes" => "client.public_notes",
"phone" => "contact.phone",
"first_name" => "contact.first_name",
"last_name" => "contact.last_name",
"email" => "contact.email",
];
protected array $invoice_report_keys = [
"invoice_number" => "invoice.number",
"amount" => "invoice.amount",
"balance" => "invoice.balance",
"paid_to_date" => "invoice.paid_to_date",
"po_number" => "invoice.po_number",
"date" => "invoice.date",
"due_date" => "invoice.due_date",
"terms" => "invoice.terms",
"footer" => "invoice.footer",
"status" => "invoice.status",
"public_notes" => "invoice.public_notes",
"private_notes" => "invoice.private_notes",
"uses_inclusive_taxes" => "invoice.uses_inclusive_taxes",
"is_amount_discount" => "invoice.is_amount_discount",
"partial" => "invoice.partial",
"partial_due_date" => "invoice.partial_due_date",
"surcharge1" => "invoice.custom_surcharge1",
"surcharge2" => "invoice.custom_surcharge2",
"surcharge3" => "invoice.custom_surcharge3",
"surcharge4" => "invoice.custom_surcharge4",
"exchange_rate" => "invoice.exchange_rate",
"tax_amount" => "invoice.total_taxes",
"assigned_user" => "invoice.assigned_user_id",
"user" => "invoice.user_id",
];
protected array $recurring_invoice_report_keys = [
"invoice_number" => "recurring_invoice.number",
"amount" => "recurring_invoice.amount",
"balance" => "recurring_invoice.balance",
"paid_to_date" => "recurring_invoice.paid_to_date",
"po_number" => "recurring_invoice.po_number",
"date" => "recurring_invoice.date",
"due_date" => "recurring_invoice.due_date",
"terms" => "recurring_invoice.terms",
"footer" => "recurring_invoice.footer",
"status" => "recurring_invoice.status",
"public_notes" => "recurring_invoice.public_notes",
"private_notes" => "recurring_invoice.private_notes",
"uses_inclusive_taxes" => "recurring_invoice.uses_inclusive_taxes",
"is_amount_discount" => "recurring_invoice.is_amount_discount",
"partial" => "recurring_invoice.partial",
"partial_due_date" => "recurring_invoice.partial_due_date",
"surcharge1" => "recurring_invoice.custom_surcharge1",
"surcharge2" => "recurring_invoice.custom_surcharge2",
"surcharge3" => "recurring_invoice.custom_surcharge3",
"surcharge4" => "recurring_invoice.custom_surcharge4",
"exchange_rate" => "recurring_invoice.exchange_rate",
"tax_amount" => "recurring_invoice.total_taxes",
"assigned_user" => "recurring_invoice.assigned_user_id",
"user" => "recurring_invoice.user_id",
"frequency_id" => "recurring_invoice.frequency_id",
"next_send_date" => "recurring_invoice.next_send_date"
];
protected array $purchase_order_report_keys = [
'amount' => 'purchase_order.amount',
'balance' => 'purchase_order.balance',
'vendor' => 'purchase_order.vendor_id',
// 'custom_surcharge1' => 'purchase_order.custom_surcharge1',
// 'custom_surcharge2' => 'purchase_order.custom_surcharge2',
// 'custom_surcharge3' => 'purchase_order.custom_surcharge3',
// 'custom_surcharge4' => 'purchase_order.custom_surcharge4',
'custom_value1' => 'purchase_order.custom_value1',
'custom_value2' => 'purchase_order.custom_value2',
'custom_value3' => 'purchase_order.custom_value3',
'custom_value4' => 'purchase_order.custom_value4',
'date' => 'purchase_order.date',
'discount' => 'purchase_order.discount',
'due_date' => 'purchase_order.due_date',
'exchange_rate' => 'purchase_order.exchange_rate',
'footer' => 'purchase_order.footer',
'number' => 'purchase_order.number',
'paid_to_date' => 'purchase_order.paid_to_date',
'partial' => 'purchase_order.partial',
'partial_due_date' => 'purchase_order.partial_due_date',
'po_number' => 'purchase_order.po_number',
'private_notes' => 'purchase_order.private_notes',
'public_notes' => 'purchase_order.public_notes',
'status' => 'purchase_order.status_id',
'tax_name1' => 'purchase_order.tax_name1',
'tax_name2' => 'purchase_order.tax_name2',
'tax_name3' => 'purchase_order.tax_name3',
'tax_rate1' => 'purchase_order.tax_rate1',
'tax_rate2' => 'purchase_order.tax_rate2',
'tax_rate3' => 'purchase_order.tax_rate3',
'terms' => 'purchase_order.terms',
'total_taxes' => 'purchase_order.total_taxes',
'currency_id' => 'purchase_order.currency_id',
];
protected array $item_report_keys = [
"quantity" => "item.quantity",
"cost" => "item.cost",
"product_key" => "item.product_key",
"notes" => "item.notes",
"item_tax1" => "item.tax_name1",
"item_tax_rate1" => "item.tax_rate1",
"item_tax2" => "item.tax_name2",
"item_tax_rate2" => "item.tax_rate2",
"item_tax3" => "item.tax_name3",
"item_tax_rate3" => "item.tax_rate3",
"custom_value1" => "item.custom_value1",
"custom_value2" => "item.custom_value2",
"custom_value3" => "item.custom_value3",
"custom_value4" => "item.custom_value4",
"discount" => "item.discount",
"type" => "item.type_id",
"tax_category" => "item.tax_id",
];
protected array $quote_report_keys = [
'custom_value1' => 'quote.custom_value1',
'custom_value2' => 'quote.custom_value2',
'custom_value3' => 'quote.custom_value3',
'custom_value4' => 'quote.custom_value4',
"number" => "quote.number",
"amount" => "quote.amount",
"balance" => "quote.balance",
"paid_to_date" => "quote.paid_to_date",
"po_number" => "quote.po_number",
"date" => "quote.date",
"valid_until" => "quote.due_date",
"terms" => "quote.terms",
"footer" => "quote.footer",
"status" => "quote.status",
"public_notes" => "quote.public_notes",
"private_notes" => "quote.private_notes",
"uses_inclusive_taxes" => "quote.uses_inclusive_taxes",
"is_amount_discount" => "quote.is_amount_discount",
"partial" => "quote.partial",
"partial_due_date" => "quote.partial_due_date",
"surcharge1" => "quote.custom_surcharge1",
"surcharge2" => "quote.custom_surcharge2",
"surcharge3" => "quote.custom_surcharge3",
"surcharge4" => "quote.custom_surcharge4",
"exchange_rate" => "quote.exchange_rate",
"tax_amount" => "quote.total_taxes",
"assigned_user" => "quote.assigned_user_id",
"user" => "quote.user_id",
];
protected array $credit_report_keys = [
"credit_number" => "credit.number",
"amount" => "credit.amount",
"balance" => "credit.balance",
"paid_to_date" => "credit.paid_to_date",
"po_number" => "credit.po_number",
"date" => "credit.date",
"due_date" => "credit.due_date",
"terms" => "credit.terms",
"footer" => "credit.footer",
"status" => "credit.status",
"public_notes" => "credit.public_notes",
"private_notes" => "credit.private_notes",
"uses_inclusive_taxes" => "credit.uses_inclusive_taxes",
"is_amount_discount" => "credit.is_amount_discount",
"partial" => "credit.partial",
"partial_due_date" => "credit.partial_due_date",
"surcharge1" => "credit.custom_surcharge1",
"surcharge2" => "credit.custom_surcharge2",
"surcharge3" => "credit.custom_surcharge3",
"surcharge4" => "credit.custom_surcharge4",
"exchange_rate" => "credit.exchange_rate",
"tax_amount" => "credit.total_taxes",
"assigned_user" => "credit.assigned_user_id",
"user" => "credit.user_id",
];
protected array $payment_report_keys = [
"date" => "payment.date",
"amount" => "payment.amount",
"refunded" => "payment.refunded",
"applied" => "payment.applied",
"transaction_reference" => "payment.transaction_reference",
"currency" => "payment.currency",
"exchange_rate" => "payment.exchange_rate",
"number" => "payment.number",
"method" => "payment.method",
"status" => "payment.status",
"private_notes" => "payment.private_notes",
"custom_value1" => "payment.custom_value1",
"custom_value2" => "payment.custom_value2",
"custom_value3" => "payment.custom_value3",
"custom_value4" => "payment.custom_value4",
"user" => "payment.user_id",
"assigned_user" => "payment.assigned_user_id",
];
protected array $expense_report_keys = [
'amount' => 'expense.amount',
'category' => 'expense.category_id',
'client' => 'expense.client_id',
'custom_value1' => 'expense.custom_value1',
'custom_value2' => 'expense.custom_value2',
'custom_value3' => 'expense.custom_value3',
'custom_value4' => 'expense.custom_value4',
'currency' => 'expense.currency_id',
'date' => 'expense.date',
'exchange_rate' => 'expense.exchange_rate',
'converted_amount' => 'expense.foreign_amount',
'invoice_currency_id' => 'expense.invoice_currency_id',
'payment_date' => 'expense.payment_date',
'number' => 'expense.number',
'payment_type_id' => 'expense.payment_type_id',
'private_notes' => 'expense.private_notes',
'project' => 'expense.project_id',
'public_notes' => 'expense.public_notes',
'tax_amount1' => 'expense.tax_amount1',
'tax_amount2' => 'expense.tax_amount2',
'tax_amount3' => 'expense.tax_amount3',
'tax_name1' => 'expense.tax_name1',
'tax_name2' => 'expense.tax_name2',
'tax_name3' => 'expense.tax_name3',
'tax_rate1' => 'expense.tax_rate1',
'tax_rate2' => 'expense.tax_rate2',
'tax_rate3' => 'expense.tax_rate3',
'transaction_reference' => 'expense.transaction_reference',
'vendor' => 'expense.vendor_id',
'invoice' => 'expense.invoice_id',
'user' => 'expense.user',
'assigned_user' => 'expense.assigned_user',
];
protected array $task_report_keys = [
'start_date' => 'task.start_date',
'end_date' => 'task.end_date',
'duration' => 'task.duration',
'rate' => 'task.rate',
'number' => 'task.number',
'description' => 'task.description',
'custom_value1' => 'task.custom_value1',
'custom_value2' => 'task.custom_value2',
'custom_value3' => 'task.custom_value3',
'custom_value4' => 'task.custom_value4',
'status' => 'task.status_id',
'project' => 'task.project_id',
];
protected function filterByClients($query)
{
if (isset($this->input['client_id']) && $this->input['client_id'] != 'all') {
@ -50,6 +366,325 @@ class BaseExport
return $query;
}
protected function resolveKey($key, $entity, $transformer) :string
{
$parts = explode(".", $key);
if(!is_array($parts) || count($parts) < 2)
return '';
$value = '';
match($parts[0]) {
'contact' => $value = $this->resolveClientContactKey($parts[1], $entity, $transformer),
'client' => $value = $this->resolveClientKey($parts[1], $entity, $transformer),
'expense' => $value = $this->resolveExpenseKey($parts[1], $entity, $transformer),
'vendor' => $value = $this->resolveVendorKey($parts[1], $entity, $transformer),
'vendor_contact' => $value = $this->resolveVendorContactKey($parts[1], $entity, $transformer),
'invoice' => $value = $this->resolveInvoiceKey($parts[1], $entity, $transformer),
'recurring_invoice' => $value = $this->resolveInvoiceKey($parts[1], $entity, $transformer),
'quote' => $value = $this->resolveQuoteKey($parts[1], $entity, $transformer),
'purchase_order' => $value = $this->resolvePurchaseOrderKey($parts[1], $entity, $transformer),
'payment' => $value = $this->resolvePaymentKey($parts[1], $entity, $transformer),
'task' => $value = $this->resolveTaskKey($parts[1], $entity, $transformer),
default => $value = '',
};
return $value;
}
private function resolveClientContactKey($column, $entity, $transformer)
{
if(!$entity->client) {
return "";
}
$primary_contact = $entity->client->primary_contact()->first() ?? $entity->client->contacts()->first();
return $primary_contact ? $primary_contact?->{$column} ?? '' : '';
}
private function resolveVendorContactKey($column, $entity, $transformer)
{
if(!$entity->vendor)
return "";
$primary_contact = $entity->vendor->primary_contact()->first() ?? $entity->vendor->contacts()->first();
return $primary_contact ? $primary_contact?->{$column} ?? '' : '';
}
private function resolveExpenseKey($column, $entity, $transformer)
{
if($column == 'user' && $entity?->expense?->user)
return $entity->expense->user->present()->name() ?? ' ';
if($column == 'assigned_user' && $entity?->expense?->assigned_user)
return $entity->expense->assigned_user->present()->name() ?? ' ';
if($column == 'category' && $entity->expense) {
return $entity->expense->category?->name ?? ' ';
}
if($entity instanceof Expense)
return '';
$transformed_entity = $transformer->includeExpense($entity);
$manager = new Manager();
$manager->setSerializer(new ArraySerializer());
$transformed_entity = $manager->createData($transformed_entity)->toArray();
if(array_key_exists($column, $transformed_entity))
return $transformed_entity[$column];
if(property_exists($entity, $column))
return $entity?->{$column} ?? '';
nlog("export: Could not resolve expense key: {$column}");
return '';
}
private function resolveTaskKey($column, $entity, $transformer)
{
// nlog("searching for {$column}");
$transformed_entity = $transformer->transform($entity);
if(array_key_exists($column, $transformed_entity)) {
return $transformed_entity[$column];
}
return '';
}
private function resolveVendorKey($column, $entity, $transformer)
{
if(!$entity->vendor)
return '';
$transformed_entity = $transformer->includeVendor($entity);
$manager = new Manager();
$manager->setSerializer(new ArraySerializer());
$transformed_entity = $manager->createData($transformed_entity)->toArray();
if($column == 'name')
return $entity->vendor->present()->name() ?: '';
if($column == 'user_id')
return $entity->vendor->user->present()->name() ?: '';
if($column == 'country_id')
return $entity->vendor->country ? ctrans("texts.country_{$entity->vendor->country->name}") : '';
if ($column == 'currency_id') {
return $entity->vendor->currency() ? $entity->vendor->currency()->code : $entity->company->currency()->code;
}
if($column == 'status')
return $entity->stringStatus($entity->status_id) ?: '';
if(array_key_exists($column, $transformed_entity))
return $transformed_entity[$column];
// nlog("export: Could not resolve vendor key: {$column}");
return '';
}
private function resolveClientKey($column, $entity, $transformer)
{
if(!$entity->client)
return '';
$transformed_client = $transformer->includeClient($entity);
$manager = new Manager();
$manager->setSerializer(new ArraySerializer());
$transformed_client = $manager->createData($transformed_client)->toArray();
if($column == 'name')
return $transformed_client['display_name'];
if($column == 'user_id')
return $entity->client->user->present()->name();
if($column == 'country_id')
return $entity->client->country ? ctrans("texts.country_{$entity->client->country->name}") : '';
if($column == 'shipping_country_id')
return $entity->client->shipping_country ? ctrans("texts.country_{$entity->client->shipping_country->name}") : '';
if($column == 'size_id')
return $entity->client->size?->name ?? '';
if($column == 'industry_id')
return $entity->client->industry?->name ?? '';
if ($column == 'currency_id') {
return $entity->client->currency() ? $entity->client->currency()->code : $entity->company->currency()->code;
}
if($column == 'client.payment_terms') {
return $entity->client->getSetting('payment_terms');
}
if(array_key_exists($column, $transformed_client))
return $transformed_client[$column];
// nlog("export: Could not resolve client key: {$column}");
return '';
}
private function resolvePurchaseOrderKey($column, $entity, $transformer)
{
// nlog("searching for {$column}");
$transformed_entity = $transformer->transform($entity);
if($column == 'status')
return $entity->stringStatus($entity->status_id);
return '';
}
private function resolveQuoteKey($column, $entity, $transformer)
{
// nlog("searching for {$column}");
$transformed_entity = $transformer->transform($entity);
if(array_key_exists($column, $transformed_entity)) {
return $transformed_entity[$column];
}
return '';
}
private function resolveInvoiceKey($column, $entity, $transformer)
{
// nlog("searching for {$column}");
$transformed_invoice = false;
if($transformer instanceof PaymentTransformer) {
$transformed_invoices = $transformer->includeInvoices($entity);
$manager = new Manager();
$manager->setSerializer(new ArraySerializer());
$transformed_invoices = $manager->createData($transformed_invoices)->toArray();
if(!isset($transformed_invoices['App\\Models\\Invoice']))
return '';
$transformed_invoices = $transformed_invoices['App\\Models\\Invoice'];
if(count($transformed_invoices) == 1 && array_key_exists($column, $transformed_invoices[0]))
return $transformed_invoices[0][$column];
if(count($transformed_invoices) > 1 && array_key_exists($column, $transformed_invoices[0]))
return implode(', ', array_column($transformed_invoices, $column));
return "";
}
if($transformer instanceof TaskTransformer) {
$transformed_invoice = $transformer->includeInvoice($entity);
if(!$transformed_invoice)
return '';
$manager = new Manager();
$manager->setSerializer(new ArraySerializer());
$transformed_invoice = $manager->createData($transformed_invoice)->toArray();
}
if($transformed_invoice && array_key_exists($column, $transformed_invoice)) {
return $transformed_invoice[$column];
} elseif ($transformed_invoice && array_key_exists(str_replace("invoice.", "", $column), $transformed_invoice)) {
return $transformed_invoice[$column];
}
return '';
}
private function resolvePaymentKey($column, $entity, $transformer)
{
if($entity instanceof Payment){
$transformed_payment = $transformer->transform($entity);
if(array_key_exists($column, $transformed_payment)) {
return $transformed_payment[$column];
} elseif (array_key_exists(str_replace("payment.", "", $column), $transformed_payment)) {
return $transformed_payment[$column];
}
// nlog("export: Could not resolve payment key: {$column}");
return '';
}
if($column == 'amount')
return $entity->payments()->exists() ? $entity->payments()->withoutTrashed()->sum('paymentables.amount') : ctrans('texts.unpaid');
if($column == 'refunded') {
return $entity->payments()->exists() ? $entity->payments()->withoutTrashed()->sum('paymentables.refunded') : '';
}
if($column == 'applied') {
$refunded = $entity->payments()->withoutTrashed()->sum('paymentables.refunded');
$amount = $entity->payments()->withoutTrashed()->sum('paymentables.amount');
return $entity->payments()->withoutTrashed()->exists() ? ($amount - $refunded) : '';
}
$payment = $entity->payments()->withoutTrashed()->first();
if(!$payment)
return '';
if($column == 'method')
return $payment->translatedType();
if($column == 'currency')
return $payment?->currency?->code ?? '';
$payment_transformer = new PaymentTransformer();
$transformed_payment = $payment_transformer->transform($payment);
if($column == 'status'){
return $payment->stringStatus($transformed_payment['status_id']);
}
if(array_key_exists($column, $transformed_payment))
return $transformed_payment[$column];
return '';
}
protected function addInvoiceStatusFilter($query, $status): Builder
{
@ -154,8 +789,27 @@ class BaseExport
$this->end_date = now()->startOfDay()->format('Y-m-d');
return $query->whereBetween($this->date_key, [now()->subDays(365), now()])->orderBy($this->date_key, 'ASC');
case 'this_year':
$this->start_date = now()->startOfYear()->format('Y-m-d');
$this->end_date = now()->format('Y-m-d');
$first_month_of_year = $this->company->getSetting('first_month_of_year') ?? 1;
$fin_year_start = now()->createFromDate(now()->year, $first_month_of_year, 1);
if(now()->lt($fin_year_start))
$fin_year_start->subYearNoOverflow();
$this->start_date = $fin_year_start->format('Y-m-d');
$this->end_date = $fin_year_start->copy()->addYear()->subDay()->format('Y-m-d');
return $query->whereBetween($this->date_key, [now()->startOfYear(), now()])->orderBy($this->date_key, 'ASC');
case 'last_year':
$first_month_of_year = $this->company->getSetting('first_month_of_year') ?? 1;
$fin_year_start = now()->createFromDate(now()->year, $first_month_of_year, 1);
$fin_year_start->subYearNoOverflow();
if(now()->subYear()->lt($fin_year_start))
$fin_year_start->subYearNoOverflow();
$this->start_date = $fin_year_start->format('Y-m-d');
$this->end_date = $fin_year_start->copy()->addYear()->subDay()->format('Y-m-d');
return $query->whereBetween($this->date_key, [now()->startOfYear(), now()])->orderBy($this->date_key, 'ASC');
case 'custom':
$this->start_date = $custom_start_date->format('Y-m-d');
@ -172,17 +826,100 @@ class BaseExport
{
$header = [];
// nlog($this->input['report_keys']);
foreach (array_merge($this->input['report_keys'], $this->forced_keys) as $value) {
$key = array_search($value, $this->entity_keys);
$prefix = '';
if(!$key) {
$prefix = stripos($value, 'client.') !== false ? ctrans('texts.client')." " : ctrans('texts.contact')." ";
$key = array_search($value, $this->client_report_keys);
}
if(!$key) {
$prefix = ctrans('texts.invoice')." ";
$key = array_search($value, $this->invoice_report_keys);
}
if(!$key) {
$prefix = ctrans('texts.recurring_invoice')." ";
$key = array_search($value, $this->recurring_invoice_report_keys);
}
if(!$key) {
$prefix = ctrans('texts.payment')." ";
$key = array_search($value, $this->payment_report_keys);
}
if(!$key) {
$prefix = ctrans('texts.quote')." ";
$key = array_search($value, $this->quote_report_keys);
}
if(!$key) {
$prefix = ctrans('texts.credit')." ";
$key = array_search($value, $this->credit_report_keys);
}
if(!$key) {
$prefix = ctrans('texts.item')." ";
$key = array_search($value, $this->item_report_keys);
}
if(!$key) {
$prefix = ctrans('texts.expense')." ";
$key = array_search($value, $this->expense_report_keys);
}
if(!$key) {
$prefix = ctrans('texts.task')." ";
$key = array_search($value, $this->task_report_keys);
}
if(!$key) {
$prefix = ctrans('texts.vendor')." ";
$key = array_search($value, $this->vendor_report_keys);
}
if(!$key) {
$prefix = ctrans('texts.purchase_order')." ";
$key = array_search($value, $this->purchase_order_report_keys);
}
if(!$key) {
$prefix = '';
}
$key = str_replace('item.', '', $key);
$key = str_replace('recurring_invoice.', '', $key);
$key = str_replace('purchase_order.', '', $key);
$key = str_replace('invoice.', '', $key);
$key = str_replace('quote.', '', $key);
$key = str_replace('credit.', '', $key);
$key = str_replace('task.', '', $key);
$key = str_replace('client.', '', $key);
$key = str_replace('vendor.', '', $key);
$key = str_replace('contact.', '', $key);
$key = str_replace('payment.', '', $key);
$key = str_replace('expense.', '', $key);
$header[] = ctrans("texts.{$key}");
if(in_array($key, ['quote1','quote2','quote3','quote4','credit1','credit2','credit3','credit4','purchase_order1','purchase_order2','purchase_order3','purchase_order4']))
{
$number = substr($key, -1);
$header[] = ctrans('texts.item') . " ". ctrans("texts.custom_value{$number}");
}
else
{
$header[] = "{$prefix}" . ctrans("texts.{$key}");
}
}
// nlog($header);
return $header;
}
}

View File

@ -22,8 +22,6 @@ use League\Csv\Writer;
class ClientExport extends BaseExport
{
private $company;
private $client_transformer;
private $contact_transformer;
@ -82,7 +80,6 @@ class ClientExport extends BaseExport
];
public array $forced_keys = [
'status',
];
public function __construct(Company $company, array $input)
@ -132,6 +129,8 @@ class ClientExport extends BaseExport
$transformed_client = $this->client_transformer->transform($client);
$transformed_contact = [];
if ($contact = $client->contacts()->first()) {
$transformed_contact = $this->contact_transformer->transform($contact);
}
@ -140,15 +139,13 @@ class ClientExport extends BaseExport
foreach (array_values($this->input['report_keys']) as $key) {
$parts = explode('.', $key);
$keyval = array_search($key, $this->entity_keys);
if ($parts[0] == 'client' && array_key_exists($parts[1], $transformed_client)) {
$entity[$keyval] = $transformed_client[$parts[1]];
} elseif ($parts[0] == 'contact' && array_key_exists($parts[1], $transformed_contact)) {
$entity[$keyval] = $transformed_contact[$parts[1]];
if (is_array($parts) && $parts[0] == 'client' && array_key_exists($parts[1], $transformed_client)) {
$entity[$key] = $transformed_client[$parts[1]];
} elseif (is_array($parts) && $parts[0] == 'contact' && array_key_exists($parts[1], $transformed_contact)) {
$entity[$key] = $transformed_contact[$parts[1]];
} else {
$entity[$keyval] = '';
$entity[$key] = '';
}
}
@ -157,24 +154,30 @@ class ClientExport extends BaseExport
private function decorateAdvancedFields(Client $client, array $entity) :array
{
if (in_array('client.user', $this->input['report_keys'])) {
$entity['client.user'] = $client->user->present()->name();
}
if (in_array('client.assigned_user', $this->input['report_keys'])) {
$entity['client.assigned_user'] = $client->assigned_user ? $client->user->present()->name() : '';
}
if (in_array('client.country_id', $this->input['report_keys'])) {
$entity['country'] = $client->country ? ctrans("texts.country_{$client->country->name}") : '';
$entity['client.country_id'] = $client->country ? ctrans("texts.country_{$client->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}") : '';
$entity['client.shipping_country_id'] = $client->shipping_country ? ctrans("texts.country_{$client->shipping_country->name}") : '';
}
if (in_array('client.currency', $this->input['report_keys'])) {
$entity['currency'] = $client->currency() ? $client->currency()->code : $client->company->currency()->code;
if (in_array('client.currency_id', $this->input['report_keys'])) {
$entity['client.currency_id'] = $client->currency() ? $client->currency()->code : $client->company->currency()->code;
}
if (in_array('client.industry_id', $this->input['report_keys'])) {
$entity['industry_id'] = $client->industry ? ctrans("texts.industry_{$client->industry->name}") : '';
}
$entity['status'] = $this->calculateStatus($client);
return $entity;
}
@ -185,7 +188,7 @@ class ClientExport extends BaseExport
}
if ($client->deleted_at) {
return ctrans('texts.arcvived');
return ctrans('texts.archived');
}
return ctrans('texts.active');

View File

@ -23,7 +23,6 @@ use League\Csv\Writer;
class ContactExport extends BaseExport
{
private Company $company;
private ClientTransformer $client_transformer;

View File

@ -21,7 +21,6 @@ use League\Csv\Writer;
class CreditExport extends BaseExport
{
private Company $company;
private CreditTransformer $credit_transformer;
@ -123,10 +122,19 @@ class CreditExport extends BaseExport
foreach (array_values($this->input['report_keys']) as $key) {
$keyval = array_search($key, $this->entity_keys);
if(!$keyval)
$keyval = array_search(str_replace("credit.", "", $key), $this->entity_keys) ?? $key;
if(!$keyval)
$keyval = $key;
if (array_key_exists($key, $transformed_credit)) {
$entity[$keyval] = $transformed_credit[$key];
} else {
$entity[$keyval] = '';
} elseif (array_key_exists($keyval, $transformed_credit)) {
$entity[$keyval] = $transformed_credit[$keyval];
}
else {
$entity[$keyval] = $this->resolveKey($keyval, $credit, $this->credit_transformer);
}
}
@ -138,9 +146,9 @@ class CreditExport extends BaseExport
if (in_array('country_id', $this->input['report_keys'])) {
$entity['country'] = $credit->client->country ? ctrans("texts.country_{$credit->client->country->name}") : '';
}
if (in_array('currency_id', $this->input['report_keys'])) {
$entity['currency_id'] = $credit->client->currency() ? $credit->client->currency()->code : $invoice->company->currency()->code;
$entity['currency_id'] = $credit->client->currency() ? $credit->client->currency()->code : $credit->company->currency()->code;
}
if (in_array('invoice_id', $this->input['report_keys'])) {
@ -155,6 +163,10 @@ class CreditExport extends BaseExport
$entity['status'] = $credit->stringStatus($credit->status_id);
}
if(in_array('credit.status', $this->input['report_keys'])) {
$entity['credit.status'] = $credit->stringStatus($credit->status_id);
}
return $entity;
}
}

View File

@ -21,7 +21,6 @@ use League\Csv\Writer;
class DocumentExport extends BaseExport
{
private Company $company;
private $entity_transformer;

View File

@ -21,7 +21,6 @@ use League\Csv\Writer;
class ExpenseExport extends BaseExport
{
private Company $company;
private $expense_transformer;
@ -30,36 +29,38 @@ class ExpenseExport extends BaseExport
public Writer $csv;
public array $entity_keys = [
'amount' => 'amount',
'category' => 'category_id',
'client' => 'client_id',
'custom_value1' => 'custom_value1',
'custom_value2' => 'custom_value2',
'custom_value3' => 'custom_value3',
'custom_value4' => 'custom_value4',
'currency' => 'currency_id',
'date' => 'date',
'exchange_rate' => 'exchange_rate',
'converted_amount' => 'foreign_amount',
'invoice_currency_id' => 'invoice_currency_id',
'payment_date' => 'payment_date',
'number' => 'number',
'payment_type_id' => 'payment_type_id',
'private_notes' => 'private_notes',
'project' => 'project_id',
'public_notes' => 'public_notes',
'tax_amount1' => 'tax_amount1',
'tax_amount2' => 'tax_amount2',
'tax_amount3' => 'tax_amount3',
'tax_name1' => 'tax_name1',
'tax_name2' => 'tax_name2',
'tax_name3' => 'tax_name3',
'tax_rate1' => 'tax_rate1',
'tax_rate2' => 'tax_rate2',
'tax_rate3' => 'tax_rate3',
'transaction_reference' => 'transaction_reference',
'vendor' => 'vendor_id',
'invoice' => 'invoice_id',
'amount' => 'expense.amount',
'category' => 'expense.category',
'client' => 'expense.client_id',
'custom_value1' => 'expense.custom_value1',
'custom_value2' => 'expense.custom_value2',
'custom_value3' => 'expense.custom_value3',
'custom_value4' => 'expense.custom_value4',
'currency' => 'expense.currency_id',
'date' => 'expense.date',
'exchange_rate' => 'expense.exchange_rate',
'converted_amount' => 'expense.foreign_amount',
'invoice_currency_id' => 'expense.invoice_currency_id',
'payment_date' => 'expense.payment_date',
'number' => 'expense.number',
'payment_type_id' => 'expense.payment_type_id',
'private_notes' => 'expense.private_notes',
'project' => 'expense.project_id',
'public_notes' => 'expense.public_notes',
'tax_amount1' => 'expense.tax_amount1',
'tax_amount2' => 'expense.tax_amount2',
'tax_amount3' => 'expense.tax_amount3',
'tax_name1' => 'expense.tax_name1',
'tax_name2' => 'expense.tax_name2',
'tax_name3' => 'expense.tax_name3',
'tax_rate1' => 'expense.tax_rate1',
'tax_rate2' => 'expense.tax_rate2',
'tax_rate3' => 'expense.tax_rate3',
'transaction_reference' => 'expense.transaction_reference',
'vendor' => 'expense.vendor_id',
'invoice' => 'expense.invoice_id',
'user' => 'expense.user',
'assigned_user' => 'expense.assigned_user',
];
private array $decorate_keys = [
@ -120,13 +121,17 @@ class ExpenseExport extends BaseExport
$entity = [];
foreach (array_values($this->input['report_keys']) as $key) {
$parts = explode('.', $key);
$keyval = array_search($key, $this->entity_keys);
if (array_key_exists($key, $transformed_expense)) {
$entity[$keyval] = $transformed_expense[$key];
if (is_array($parts) && $parts[0] == 'expense' && array_key_exists($parts[1], $transformed_expense)) {
$entity[$key] = $transformed_expense[$parts[1]];
} elseif (array_key_exists($key, $transformed_expense)) {
$entity[$key] = $transformed_expense[$key];
} else {
$entity[$keyval] = '';
$entity[$key] = $this->resolveKey($key, $expense, $this->expense_transformer);
}
}
return $this->decorateAdvancedFields($expense, $entity);
@ -134,32 +139,40 @@ class ExpenseExport extends BaseExport
private function decorateAdvancedFields(Expense $expense, array $entity) :array
{
if (in_array('currency_id', $this->input['report_keys'])) {
$entity['currency'] = $expense->currency ? $expense->currency->code : '';
if (in_array('expense.currency_id', $this->input['report_keys'])) {
$entity['expense.currency_id'] = $expense->currency ? $expense->currency->code : '';
}
if (in_array('client_id', $this->input['report_keys'])) {
$entity['client'] = $expense->client ? $expense->client->present()->name() : '';
if (in_array('expense.client_id', $this->input['report_keys'])) {
$entity['expense.client'] = $expense->client ? $expense->client->present()->name() : '';
}
if (in_array('invoice_id', $this->input['report_keys'])) {
$entity['invoice'] = $expense->invoice ? $expense->invoice->number : '';
if (in_array('expense.invoice_id', $this->input['report_keys'])) {
$entity['expense.invoice_id'] = $expense->invoice ? $expense->invoice->number : '';
}
if (in_array('category_id', $this->input['report_keys'])) {
$entity['category'] = $expense->category ? $expense->category->name : '';
if (in_array('expense.category', $this->input['report_keys'])) {
$entity['expense.category'] = $expense->category ? $expense->category->name : '';
}
if (in_array('vendor_id', $this->input['report_keys'])) {
$entity['vendor'] = $expense->vendor ? $expense->vendor->name : '';
if (in_array('expense.vendor_id', $this->input['report_keys'])) {
$entity['expense.vendor'] = $expense->vendor ? $expense->vendor->name : '';
}
if (in_array('payment_type_id', $this->input['report_keys'])) {
$entity['payment_type'] = $expense->payment_type ? $expense->payment_type->name : '';
if (in_array('expense.payment_type_id', $this->input['report_keys'])) {
$entity['expense.payment_type_id'] = $expense->payment_type ? $expense->payment_type->name : '';
}
if (in_array('project_id', $this->input['report_keys'])) {
$entity['project'] = $expense->project ? $expense->project->name : '';
if (in_array('expense.project_id', $this->input['report_keys'])) {
$entity['expense.project_id'] = $expense->project ? $expense->project->name : '';
}
if (in_array('expense.user', $this->input['report_keys'])) {
$entity['expense.user'] = $expense->user ? $expense->user->present()->name() : '';
}
if (in_array('expense.assigned_user', $this->input['report_keys'])) {
$entity['expense.assigned_user'] = $expense->assigned_user ? $expense->assigned_user->present()->name() : '';
}
return $entity;

View File

@ -23,8 +23,6 @@ use App\Transformers\InvoiceTransformer;
class InvoiceExport extends BaseExport
{
private Company $company;
private $invoice_transformer;
public string $date_key = 'date';
@ -80,6 +78,7 @@ class InvoiceExport extends BaseExport
'project',
];
public function __construct(Company $company, array $input)
{
$this->company = $company;
@ -134,10 +133,21 @@ class InvoiceExport extends BaseExport
foreach (array_values($this->input['report_keys']) as $key) {
$keyval = array_search($key, $this->entity_keys);
if(!$keyval) {
$keyval = array_search(str_replace("invoice.", "", $key), $this->entity_keys) ?? $key;
}
if(!$keyval) {
$keyval = $key;
}
if (array_key_exists($key, $transformed_invoice)) {
$entity[$keyval] = $transformed_invoice[$key];
} else {
$entity[$keyval] = '';
} elseif (array_key_exists($keyval, $transformed_invoice)) {
$entity[$keyval] = $transformed_invoice[$keyval];
}
else {
$entity[$keyval] = $this->resolveKey($keyval, $invoice, $this->invoice_transformer);
}
}
@ -162,15 +172,15 @@ class InvoiceExport extends BaseExport
$entity['status'] = $invoice->stringStatus($invoice->status_id);
}
$payment_exists = $invoice->payments()->exists();
// $payment_exists = $invoice->payments()->exists();
$entity['payment_number'] = $payment_exists ? $invoice->payments()->pluck('number')->implode(',') : '';
// $entity['payment_number'] = $payment_exists ? $invoice->payments()->pluck('number')->implode(',') : '';
$entity['payment_date'] = $payment_exists ? $invoice->payments()->pluck('date')->implode(',') : '';
// $entity['payment_date'] = $payment_exists ? $invoice->payments()->pluck('date')->implode(',') : '';
$entity['payment_amount'] = $payment_exists ? Number::formatMoney($invoice->payments()->sum('paymentables.amount'), $invoice->company) : ctrans('texts.unpaid');
// $entity['payment_amount'] = $payment_exists ? Number::formatMoney($invoice->payments()->sum('paymentables.amount'), $invoice->company) : ctrans('texts.unpaid');
$entity['method'] = $payment_exists ? $invoice->payments()->first()->translatedType() : "";
// $entity['method'] = $payment_exists ? $invoice->payments()->first()->translatedType() : "";
return $entity;
}

View File

@ -22,7 +22,6 @@ use League\Csv\Writer;
class InvoiceItemExport extends BaseExport
{
private Company $company;
private $invoice_transformer;
@ -30,6 +29,8 @@ class InvoiceItemExport extends BaseExport
public Writer $csv;
private bool $force_keys = false;
public array $entity_keys = [
'amount' => 'amount',
'balance' => 'balance',
@ -67,9 +68,9 @@ class InvoiceItemExport extends BaseExport
'total_taxes' => 'total_taxes',
'currency' => 'currency_id',
'quantity' => 'item.quantity',
'unit_cost' => 'item.cost',
'cost' => 'item.cost',
'product_key' => 'item.product_key',
'cost' => 'item.product_cost',
'buy_price' => 'item.product_cost',
'notes' => 'item.notes',
'discount' => 'item.discount',
'is_amount_discount' => 'item.is_amount_discount',
@ -85,6 +86,8 @@ class InvoiceItemExport extends BaseExport
'invoice2' => 'item.custom_value2',
'invoice3' => 'item.custom_value3',
'invoice4' => 'item.custom_value4',
'tax_category' => 'item.tax_id',
'type' => 'item.type_id',
];
private array $decorate_keys = [
@ -112,6 +115,7 @@ class InvoiceItemExport extends BaseExport
$this->csv = Writer::createFromString();
if (count($this->input['report_keys']) == 0) {
$this->force_keys = true;
$this->input['report_keys'] = array_values($this->entity_keys);
}
@ -140,24 +144,36 @@ class InvoiceItemExport extends BaseExport
$transformed_items = [];
foreach ($invoice->line_items as $item) {
$item_array = [];
$item_array = [];
foreach (array_values($this->input['report_keys']) as $key) {
foreach (array_values($this->input['report_keys']) as $key) { //items iterator produces item array
if (str_contains($key, "item.")) {
$key = str_replace("item.", "", $key);
$keyval = $key;
$keyval = str_replace("custom_value", "invoice", $key);
if($key == 'type_id')
$keyval = 'type';
if($key == 'tax_id')
$keyval = 'tax_category';
if (property_exists($item, $key)) {
$item_array[$key] = $item->{$key};
$item_array[$keyval] = $item->{$key};
} else {
$item_array[$key] = '';
$item_array[$keyval] = '';
}
}
}
$entity = [];
foreach (array_values($this->input['report_keys']) as $key) {
$keyval = array_search($key, $this->entity_keys);
foreach (array_values($this->input['report_keys']) as $key) { //create an array of report keys only
$keyval = array_search($key, $this->entity_keys);
if (array_key_exists($key, $transformed_items)) {
$entity[$keyval] = $transformed_items[$key];
@ -182,10 +198,21 @@ class InvoiceItemExport extends BaseExport
foreach (array_values($this->input['report_keys']) as $key) {
$keyval = array_search($key, $this->entity_keys);
if(!$keyval) {
$keyval = array_search(str_replace("invoice.", "", $key), $this->entity_keys) ?? $key;
}
if(!$keyval) {
$keyval = $key;
}
if (array_key_exists($key, $transformed_invoice)) {
$entity[$keyval] = $transformed_invoice[$key];
} else {
$entity[$keyval] = "";
} elseif (array_key_exists($keyval, $transformed_invoice)) {
$entity[$keyval] = $transformed_invoice[$keyval];
}
else {
$entity[$keyval] = $this->resolveKey($keyval, $invoice, $this->invoice_transformer);
}
}
@ -198,13 +225,20 @@ class InvoiceItemExport extends BaseExport
$entity['currency'] = $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();
$entity['client_id_number'] = $invoice->client->id_number;
$entity['client_number'] = $invoice->client->number;
if(array_key_exists('type', $entity)) {
$entity['type'] = $invoice->typeIdString($entity['type']);
}
// if(in_array('status_id', $this->input['report_keys']))
$entity['status'] = $invoice->stringStatus($invoice->status_id);
if(array_key_exists('tax_category', $entity)) {
$entity['tax_category'] = $invoice->taxTypeString($entity['tax_category']);
}
if($this->force_keys) {
$entity['client'] = $invoice->client->present()->name();
$entity['client_id_number'] = $invoice->client->id_number;
$entity['client_number'] = $invoice->client->number;
$entity['status'] = $invoice->stringStatus($invoice->status_id);
}
return $entity;
}

View File

@ -21,8 +21,6 @@ use League\Csv\Writer;
class PaymentExport extends BaseExport
{
private Company $company;
private $entity_transformer;
public string $date_key = 'date';
@ -112,10 +110,21 @@ class PaymentExport extends BaseExport
foreach (array_values($this->input['report_keys']) as $key) {
$keyval = array_search($key, $this->entity_keys);
if(!$keyval) {
$keyval = array_search(str_replace("payment.", "", $key), $this->entity_keys) ?? $key;
}
if(!$keyval) {
$keyval = $key;
}
if (array_key_exists($key, $transformed_entity)) {
$entity[$keyval] = $transformed_entity[$key];
} else {
$entity[$keyval] = '';
} elseif (array_key_exists($keyval, $transformed_entity)) {
$entity[$keyval] = $transformed_entity[$keyval];
}
else {
$entity[$keyval] = $this->resolveKey($keyval, $payment, $this->entity_transformer);
}
}
@ -140,6 +149,10 @@ class PaymentExport extends BaseExport
$entity['currency'] = $payment->currency()->exists() ? $payment->currency->code : '';
}
if (in_array('payment.currency', $this->input['report_keys'])) {
$entity['payment.currency'] = $payment->currency()->exists() ? $payment->currency->code : '';
}
if (in_array('exchange_currency_id', $this->input['report_keys'])) {
$entity['exchange_currency'] = $payment->exchange_currency()->exists() ? $payment->exchange_currency->code : '';
}
@ -152,11 +165,19 @@ class PaymentExport extends BaseExport
$entity['type'] = $payment->translatedType();
}
if (in_array('payment.method', $this->input['report_keys'])) {
$entity['payment.method'] = $payment->translatedType();
}
if (in_array('payment.status', $this->input['report_keys'])) {
$entity['payment.status'] = $payment->stringStatus($payment->status_id);
}
if (in_array('gateway_type_id', $this->input['report_keys'])) {
$entity['gateway'] = $payment->gateway_type ? $payment->gateway_type->name : 'Unknown Type';
}
$entity['invoices'] = $payment->invoices()->exists() ? $payment->invoices->pluck('number')->implode(',') : '';
// $entity['invoices'] = $payment->invoices()->exists() ? $payment->invoices->pluck('number')->implode(',') : '';
return $entity;
}

View File

@ -22,8 +22,6 @@ use League\Csv\Writer;
class ProductExport extends BaseExport
{
private Company $company;
private $entity_transformer;
public string $date_key = 'created_at';

View File

@ -23,8 +23,6 @@ use League\Csv\Writer;
class ProductSalesExport extends BaseExport
{
private Company $company;
public string $date_key = 'created_at';
protected Collection $products;

View File

@ -0,0 +1,171 @@
<?php
/**
* PurchaseOrder Ninja (https://invoiceninja.com).
*
* @link https://github.com/invoiceninja/invoiceninja source repository
*
* @copyright Copyright (c) 2023. PurchaseOrder Ninja LLC (https://invoiceninja.com)
*
* @license https://www.elastic.co/licensing/elastic-license
*/
namespace App\Export\CSV;
use App\Libraries\MultiDB;
use App\Models\Company;
use App\Models\PurchaseOrder;
use App\Transformers\PurchaseOrderTransformer;
use App\Utils\Ninja;
use App\Utils\Number;
use Illuminate\Support\Facades\App;
use League\Csv\Writer;
class PurchaseOrderExport extends BaseExport
{
private $purchase_order_transformer;
public string $date_key = 'date';
public Writer $csv;
public array $entity_keys = [
'amount' => 'purchase_order.amount',
'balance' => 'purchase_order.balance',
'vendor' => 'purchase_order.vendor_id',
// 'custom_surcharge1' => 'purchase_order.custom_surcharge1',
// 'custom_surcharge2' => 'purchase_order.custom_surcharge2',
// 'custom_surcharge3' => 'purchase_order.custom_surcharge3',
// 'custom_surcharge4' => 'purchase_order.custom_surcharge4',
'custom_value1' => 'purchase_order.custom_value1',
'custom_value2' => 'purchase_order.custom_value2',
'custom_value3' => 'purchase_order.custom_value3',
'custom_value4' => 'purchase_order.custom_value4',
'date' => 'purchase_order.date',
'discount' => 'purchase_order.discount',
'due_date' => 'purchase_order.due_date',
'exchange_rate' => 'purchase_order.exchange_rate',
'footer' => 'purchase_order.footer',
'number' => 'purchase_order.number',
'paid_to_date' => 'purchase_order.paid_to_date',
'partial' => 'purchase_order.partial',
'partial_due_date' => 'purchase_order.partial_due_date',
'po_number' => 'purchase_order.po_number',
'private_notes' => 'purchase_order.private_notes',
'public_notes' => 'purchase_order.public_notes',
'status' => 'purchase_order.status_id',
'tax_name1' => 'purchase_order.tax_name1',
'tax_name2' => 'purchase_order.tax_name2',
'tax_name3' => 'purchase_order.tax_name3',
'tax_rate1' => 'purchase_order.tax_rate1',
'tax_rate2' => 'purchase_order.tax_rate2',
'tax_rate3' => 'purchase_order.tax_rate3',
'terms' => 'purchase_order.terms',
'total_taxes' => 'purchase_order.total_taxes',
'currency_id' => 'purchase_order.currency_id',
];
private array $decorate_keys = [
'country',
'currency_id',
'status',
'vendor',
'project',
];
public function __construct(Company $company, array $input)
{
$this->company = $company;
$this->input = $input;
$this->purchase_order_transformer = new PurchaseOrderTransformer();
}
public function run()
{
MultiDB::setDb($this->company->db);
App::forgetInstance('translator');
App::setLocale($this->company->locale());
$t = app('translator');
$t->replace(Ninja::transformTranslations($this->company->settings));
//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());
$query = PurchaseOrder::query()
->withTrashed()
->with('vendor')
->where('company_id', $this->company->id)
->where('is_deleted', 0);
$query = $this->addDateRange($query);
// if(isset($this->input['status'])) {
// $query = $this->addPurchaseOrderStatusFilter($query, $this->input['status']);
// }
$query->cursor()
->each(function ($purchase_order) {
$this->csv->insertOne($this->buildRow($purchase_order));
});
return $this->csv->toString();
}
private function buildRow(PurchaseOrder $purchase_order) :array
{
$transformed_purchase_order = $this->purchase_order_transformer->transform($purchase_order);
$entity = [];
foreach (array_values($this->input['report_keys']) as $key) {
$keyval = array_search($key, $this->entity_keys);
if(!$keyval) {
$keyval = array_search(str_replace("purchase_order.", "", $key), $this->entity_keys) ?? $key;
}
if(!$keyval) {
$keyval = $key;
}
if (array_key_exists($key, $transformed_purchase_order)) {
$entity[$keyval] = $transformed_purchase_order[$key];
} elseif (array_key_exists($keyval, $transformed_purchase_order)) {
$entity[$keyval] = $transformed_purchase_order[$keyval];
} else {
$entity[$keyval] = $this->resolveKey($keyval, $purchase_order, $this->purchase_order_transformer);
}
}
return $this->decorateAdvancedFields($purchase_order, $entity);
}
private function decorateAdvancedFields(PurchaseOrder $purchase_order, array $entity) :array
{
if (in_array('country_id', $this->input['report_keys'])) {
$entity['country'] = $purchase_order->vendor->country ? ctrans("texts.country_{$purchase_order->vendor->country->name}") : '';
}
if (in_array('currency_id', $this->input['report_keys'])) {
$entity['currency_id'] = $purchase_order->vendor->currency() ? $purchase_order->vendor->currency()->code : $purchase_order->company->currency()->code;
}
if (in_array('vendor_id', $this->input['report_keys'])) {
$entity['vendor'] = $purchase_order->vendor->present()->name();
}
if (in_array('status_id', $this->input['report_keys'])) {
$entity['status'] = $purchase_order->stringStatus($purchase_order->status_id);
}
return $entity;
}
}

View File

@ -0,0 +1,245 @@
<?php
/**
* PurchaseOrder Ninja (https://invoiceninja.com).
*
* @link https://github.com/invoiceninja/invoiceninja source repository
*
* @copyright Copyright (c) 2023. PurchaseOrder Ninja LLC (https://invoiceninja.com)
*
* @license https://www.elastic.co/licensing/elastic-license
*/
namespace App\Export\CSV;
use App\Libraries\MultiDB;
use App\Models\Company;
use App\Models\PurchaseOrder;
use App\Transformers\PurchaseOrderTransformer;
use App\Utils\Ninja;
use Illuminate\Support\Facades\App;
use League\Csv\Writer;
class PurchaseOrderItemExport extends BaseExport
{
private $purchase_order_transformer;
public string $date_key = 'date';
public Writer $csv;
private bool $force_keys = false;
public array $entity_keys = [
'amount' => 'amount',
'balance' => 'balance',
'vendor' => 'vendor_id',
'vendor_number' => 'vendor.number',
'vendor_id_number' => 'vendor.id_number',
// 'custom_surcharge1' => 'custom_surcharge1',
// 'custom_surcharge2' => 'custom_surcharge2',
// 'custom_surcharge3' => 'custom_surcharge3',
// 'custom_surcharge4' => 'custom_surcharge4',
// 'custom_value1' => 'custom_value1',
// 'custom_value2' => 'custom_value2',
// 'custom_value3' => 'custom_value3',
// 'custom_value4' => 'custom_value4',
'date' => 'date',
'discount' => 'discount',
'due_date' => 'due_date',
'exchange_rate' => 'exchange_rate',
'footer' => 'footer',
'number' => 'number',
'paid_to_date' => 'paid_to_date',
'partial' => 'partial',
'partial_due_date' => 'partial_due_date',
'po_number' => 'po_number',
'private_notes' => 'private_notes',
'public_notes' => 'public_notes',
'status' => 'status_id',
'tax_name1' => 'tax_name1',
'tax_name2' => 'tax_name2',
'tax_name3' => 'tax_name3',
'tax_rate1' => 'tax_rate1',
'tax_rate2' => 'tax_rate2',
'tax_rate3' => 'tax_rate3',
'terms' => 'terms',
'total_taxes' => 'total_taxes',
'currency' => 'currency_id',
'quantity' => 'item.quantity',
'cost' => 'item.cost',
'product_key' => 'item.product_key',
'buy_price' => 'item.product_cost',
'notes' => 'item.notes',
'discount' => 'item.discount',
'is_amount_discount' => 'item.is_amount_discount',
'tax_rate1' => 'item.tax_rate1',
'tax_rate2' => 'item.tax_rate2',
'tax_rate3' => 'item.tax_rate3',
'tax_name1' => 'item.tax_name1',
'tax_name2' => 'item.tax_name2',
'tax_name3' => 'item.tax_name3',
'line_total' => 'item.line_total',
'gross_line_total' => 'item.gross_line_total',
'purchase_order1' => 'item.custom_value1',
'purchase_order2' => 'item.custom_value2',
'purchase_order3' => 'item.custom_value3',
'purchase_order4' => 'item.custom_value4',
'tax_category' => 'item.tax_id',
'type' => 'item.type_id',
];
private array $decorate_keys = [
'client',
'currency_id',
'status'
];
public function __construct(Company $company, array $input)
{
$this->company = $company;
$this->input = $input;
$this->purchase_order_transformer = new PurchaseOrderTransformer();
}
public function run()
{
MultiDB::setDb($this->company->db);
App::forgetInstance('translator');
App::setLocale($this->company->locale());
$t = app('translator');
$t->replace(Ninja::transformTranslations($this->company->settings));
//load the CSV document from a string
$this->csv = Writer::createFromString();
if (count($this->input['report_keys']) == 0) {
$this->force_keys = true;
$this->input['report_keys'] = array_values($this->entity_keys);
}
//insert the header
$this->csv->insertOne($this->buildHeader());
$query = PurchaseOrder::query()
->withTrashed()
->with('vendor')->where('company_id', $this->company->id)
->where('is_deleted', 0);
$query = $this->addDateRange($query);
$query->cursor()
->each(function ($purchase_order) {
$this->iterateItems($purchase_order);
});
return $this->csv->toString();
}
private function iterateItems(PurchaseOrder $purchase_order)
{
$transformed_purchase_order = $this->buildRow($purchase_order);
$transformed_items = [];
foreach ($purchase_order->line_items as $item) {
$item_array = [];
foreach (array_values($this->input['report_keys']) as $key) { //items iterator produces item array
if (str_contains($key, "item.")) {
$key = str_replace("item.", "", $key);
$keyval = $key;
$keyval = str_replace("custom_value", "purchase_order", $key);
if($key == 'type_id') {
$keyval = 'type';
}
if($key == 'tax_id') {
$keyval = 'tax_category';
}
if (property_exists($item, $key)) {
$item_array[$keyval] = $item->{$key};
} else {
$item_array[$keyval] = '';
}
}
}
$entity = [];
foreach (array_values($this->input['report_keys']) as $key) { //create an array of report keys only
$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_purchase_order, $item_array);
$entity = $this->decorateAdvancedFields($purchase_order, $transformed_items);
$this->csv->insertOne($entity);
}
}
private function buildRow(PurchaseOrder $purchase_order) :array
{
$transformed_purchase_order = $this->purchase_order_transformer->transform($purchase_order);
$entity = [];
foreach (array_values($this->input['report_keys']) as $key) {
$keyval = array_search($key, $this->entity_keys);
if(!$keyval) {
$keyval = array_search(str_replace("purchase_order.", "", $key), $this->entity_keys) ?? $key;
}
if(!$keyval) {
$keyval = $key;
}
if (array_key_exists($key, $transformed_purchase_order)) {
$entity[$keyval] = $transformed_purchase_order[$key];
} elseif (array_key_exists($keyval, $transformed_purchase_order)) {
$entity[$keyval] = $transformed_purchase_order[$keyval];
} else {
$entity[$keyval] = $this->resolveKey($keyval, $purchase_order, $this->purchase_order_transformer);
}
}
return $this->decorateAdvancedFields($purchase_order, $entity);
}
private function decorateAdvancedFields(PurchaseOrder $purchase_order, array $entity) :array
{
if (in_array('currency_id', $this->input['report_keys'])) {
$entity['currency'] = $purchase_order->vendor->currency() ? $purchase_order->vendor->currency()->code : $purchase_order->company->currency()->code;
}
if(array_key_exists('type', $entity)) {
$entity['type'] = $purchase_order->typeIdString($entity['type']);
}
if(array_key_exists('tax_category', $entity)) {
$entity['tax_category'] = $purchase_order->taxTypeString($entity['tax_category']);
}
if($this->force_keys) {
$entity['vendor'] = $purchase_order->vendor->present()->name();
$entity['vendor_id_number'] = $purchase_order->vendor->id_number;
$entity['vendor_number'] = $purchase_order->vendor->number;
$entity['status'] = $purchase_order->stringStatus($purchase_order->status_id);
}
return $entity;
}
}

View File

@ -21,7 +21,6 @@ use League\Csv\Writer;
class QuoteExport extends BaseExport
{
private Company $company;
private $quote_transformer;
@ -43,7 +42,7 @@ class QuoteExport extends BaseExport
'custom_value4' => 'custom_value4',
'date' => 'date',
'discount' => 'discount',
'due_date' => 'due_date',
'valid_until' => 'due_date',
'exchange_rate' => 'exchange_rate',
'footer' => 'footer',
'number' => 'number',
@ -115,17 +114,28 @@ class QuoteExport extends BaseExport
private function buildRow(Quote $quote) :array
{
$transformed_quote = $this->quote_transformer->transform($quote);
$transformed_entity = $this->quote_transformer->transform($quote);
$entity = [];
foreach (array_values($this->input['report_keys']) as $key) {
$keyval = array_search($key, $this->entity_keys);
if (array_key_exists($key, $transformed_quote)) {
$entity[$keyval] = $transformed_quote[$key];
} else {
$entity[$keyval] = '';
if(!$keyval) {
$keyval = array_search(str_replace("invoice.", "", $key), $this->entity_keys) ?? $key;
}
if(!$keyval) {
$keyval = $key;
}
if (array_key_exists($key, $transformed_entity)) {
$entity[$keyval] = $transformed_entity[$key];
} elseif (array_key_exists($keyval, $transformed_entity)) {
$entity[$keyval] = $transformed_entity[$keyval];
}
else {
$entity[$keyval] = $this->resolveKey($keyval, $quote, $this->quote_transformer);
}
}

View File

@ -21,7 +21,6 @@ use League\Csv\Writer;
class QuoteItemExport extends BaseExport
{
private Company $company;
private $quote_transformer;
@ -63,10 +62,11 @@ class QuoteItemExport extends BaseExport
'terms' => 'terms',
'total_taxes' => 'total_taxes',
'currency' => 'currency_id',
'qty' => 'item.quantity',
'unit_cost' => 'item.cost',
'quantity' => 'item.quantity',
'cost' => 'item.cost',
'product_key' => 'item.product_key',
'cost' => 'item.product_cost',
'buy_price' => 'item.product_cost',
'cost' => 'item.cost',
'notes' => 'item.notes',
'discount' => 'item.discount',
'is_amount_discount' => 'item.is_amount_discount',
@ -77,11 +77,13 @@ class QuoteItemExport extends BaseExport
'tax_name2' => 'item.tax_name2',
'tax_name3' => 'item.tax_name3',
'line_total' => 'item.line_total',
// 'gross_line_total' => 'item.gross_line_total',
'custom_value1' => 'item.custom_value1',
'custom_value2' => 'item.custom_value2',
'custom_value3' => 'item.custom_value3',
'custom_value4' => 'item.custom_value4',
'gross_line_total' => 'item.gross_line_total',
'quote1' => 'item.custom_value1',
'quote2' => 'item.custom_value2',
'quote3' => 'item.custom_value3',
'quote4' => 'item.custom_value4',
'tax_category' => 'item.tax_id',
'type' => 'item.type_id',
];
private array $decorate_keys = [
@ -135,25 +137,44 @@ class QuoteItemExport extends BaseExport
$transformed_items = [];
foreach ($quote->line_items as $item) {
$item_array = [];
$transformed_items = [];
foreach (array_values($this->input['report_keys']) as $key) {
if (str_contains($key, 'item.')) {
$key = str_replace('item.', '', $key);
$item_array[$key] = $item->{$key};
foreach ($quote->line_items as $item) {
$item_array = [];
foreach (array_values($this->input['report_keys']) as $key) { //items iterator produces item array
if (str_contains($key, "item.")) {
$key = str_replace("item.", "", $key);
$keyval = $key;
$keyval = str_replace("custom_value", "quote", $key);
if($key == 'type_id')
$keyval = 'type';
if($key == 'tax_id')
$keyval = 'tax_category';
if (property_exists($item, $key)) {
$item_array[$keyval] = $item->{$key};
} else {
$item_array[$keyval] = '';
}
}
}
$entity = [];
foreach (array_values($this->input['report_keys']) as $key) {
$keyval = array_search($key, $this->entity_keys);
foreach (array_values($this->input['report_keys']) as $key) { //create an array of report keys only
$keyval = array_search($key, $this->entity_keys);
if (array_key_exists($key, $transformed_items)) {
$entity[$keyval] = $transformed_items[$key];
} else {
$entity[$keyval] = '';
$entity[$keyval] = "";
}
}
@ -173,16 +194,26 @@ class QuoteItemExport extends BaseExport
foreach (array_values($this->input['report_keys']) as $key) {
$keyval = array_search($key, $this->entity_keys);
if(!$keyval) {
$keyval = array_search(str_replace("quote.", "", $key), $this->entity_keys) ?? $key;
}
if(!$keyval) {
$keyval = $key;
}
if (array_key_exists($key, $transformed_quote)) {
$entity[$keyval] = $transformed_quote[$key];
} else {
$entity[$keyval] = '';
} elseif (array_key_exists($keyval, $transformed_quote)) {
$entity[$keyval] = $transformed_quote[$keyval];
}
else {
$entity[$keyval] = $this->resolveKey($keyval, $quote, $this->quote_transformer);
}
}
return $this->decorateAdvancedFields($quote, $entity);
}
private function decorateAdvancedFields(Quote $quote, array $entity) :array
{
if (in_array('currency_id', $this->input['report_keys'])) {

View File

@ -21,7 +21,6 @@ use League\Csv\Writer;
class RecurringInvoiceExport extends BaseExport
{
private Company $company;
private $invoice_transformer;
@ -33,10 +32,10 @@ class RecurringInvoiceExport extends BaseExport
'amount' => 'amount',
'balance' => 'balance',
'client' => 'client_id',
'custom_surcharge1' => 'custom_surcharge1',
'custom_surcharge2' => 'custom_surcharge2',
'custom_surcharge3' => 'custom_surcharge3',
'custom_surcharge4' => 'custom_surcharge4',
// 'custom_surcharge1' => 'custom_surcharge1',
// 'custom_surcharge2' => 'custom_surcharge2',
// 'custom_surcharge3' => 'custom_surcharge3',
// 'custom_surcharge4' => 'custom_surcharge4',
'custom_value1' => 'custom_value1',
'custom_value2' => 'custom_value2',
'custom_value3' => 'custom_value3',
@ -66,7 +65,8 @@ class RecurringInvoiceExport extends BaseExport
'currency' => 'currency_id',
'vendor' => 'vendor_id',
'project' => 'project_id',
'frequency' => 'frequency_id'
'frequency_id' => 'frequency_id',
'next_send_date' => 'next_send_date'
];
private array $decorate_keys = [
@ -127,11 +127,22 @@ class RecurringInvoiceExport extends BaseExport
foreach (array_values($this->input['report_keys']) as $key) {
$keyval = array_search($key, $this->entity_keys);
if(!$keyval) {
$keyval = array_search(str_replace("recurring_invoice.", "", $key), $this->entity_keys) ?? $key;
}
if(!$keyval) {
$keyval = $key;
}
if (array_key_exists($key, $transformed_invoice)) {
$entity[$keyval] = $transformed_invoice[$key];
} elseif (array_key_exists($keyval, $transformed_invoice)) {
$entity[$keyval] = $transformed_invoice[$keyval];
} else {
$entity[$keyval] = '';
$entity[$keyval] = $this->resolveKey($keyval, $invoice, $this->invoice_transformer);
}
}
return $this->decorateAdvancedFields($invoice, $entity);
@ -163,7 +174,9 @@ class RecurringInvoiceExport extends BaseExport
$entity['vendor'] = $invoice->vendor ? $invoice->vendor->name : '';
}
$entity['frequency'] = $invoice->frequencyForKey($invoice->frequency_id);
if (in_array('recurring_invoice.frequency_id', $this->input['report_keys']) || in_array('frequency_id', $this->input['report_keys'])) {
$entity['frequency_id'] = $invoice->frequencyForKey($invoice->frequency_id);
}
return $entity;
}

View File

@ -24,7 +24,6 @@ use League\Csv\Writer;
class TaskExport extends BaseExport
{
private Company $company;
private $entity_transformer;
@ -47,9 +46,7 @@ class TaskExport extends BaseExport
'custom_value4' => 'custom_value4',
'status' => 'status_id',
'project' => 'project_id',
'invoice' => 'invoice_id',
'client' => 'client_id',
];
];
private array $decorate_keys = [
'status',
@ -110,38 +107,39 @@ class TaskExport extends BaseExport
$entity = [];
$transformed_entity = $this->entity_transformer->transform($task);
foreach (array_values($this->input['report_keys']) as $key) {
$keyval = array_search($key, $this->entity_keys);
if(!$keyval) {
$keyval = array_search(str_replace("task.", "", $key), $this->entity_keys) ?? $key;
}
if(!$keyval) {
$keyval = $key;
}
if (array_key_exists($key, $transformed_entity)) {
$entity[$keyval] = $transformed_entity[$key];
} elseif (array_key_exists($keyval, $transformed_entity)) {
$entity[$keyval] = $transformed_entity[$keyval];
}
else {
$entity[$keyval] = $this->resolveKey($keyval, $task, $this->entity_transformer);
}
}
$entity['start_date'] = '';
$entity['end_date'] = '';
$entity['duration'] = '';
if (is_null($task->time_log) || (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) {
$keyval = array_search($key, $this->entity_keys);
if (array_key_exists($key, $transformed_entity)) {
$entity[$keyval] = $transformed_entity[$key];
} else {
$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) {
$keyval = array_search($key, $this->entity_keys);
if (array_key_exists($key, $transformed_entity)) {
$entity[$keyval] = $transformed_entity[$key];
} else {
$entity[$keyval] = '';
}
}
} else {
$this->iterateLogs($task, $entity);
}
}
private function iterateLogs(Task $task, array $entity)
@ -164,39 +162,26 @@ class TaskExport extends BaseExport
}
foreach ($logs as $key => $item) {
if (in_array('start_date', $this->input['report_keys'])) {
if (in_array('task.start_date', $this->input['report_keys']) || 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) {
if ((in_array('task.end_date', $this->input['report_keys']) || 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('task.end_date', $this->input['report_keys']) || in_array('end_date', $this->input['report_keys'])) && $item[1] == 0) {
$entity['end_date'] = ctrans('texts.is_running');
}
if (in_array('duration', $this->input['report_keys'])) {
if (in_array('task.duration', $this->input['report_keys']) || in_array('duration', $this->input['report_keys'])) {
$entity['duration'] = $task->calcDuration();
}
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']);
unset($entity['end_date']);
unset($entity['duration']);
@ -213,14 +198,6 @@ class TaskExport extends BaseExport
$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;
}
}

View File

@ -0,0 +1,171 @@
<?php
/**
* Invoice Ninja (https://invoiceninja.com).
*
* @link https://github.com/invoiceninja/invoiceninja source repository
*
* @copyright Copyright (c) 2023. Invoice Ninja LLC (https://invoiceninja.com)
*
* @license https://www.elastic.co/licensing/elastic-license
*/
namespace App\Export\CSV;
use App\Libraries\MultiDB;
use App\Models\Vendor;
use App\Models\Company;
use App\Transformers\VendorContactTransformer;
use App\Transformers\VendorTransformer;
use App\Utils\Ninja;
use Illuminate\Support\Facades\App;
use League\Csv\Writer;
class VendorExport extends BaseExport
{
private $vendor_transformer;
private $contact_transformer;
public Writer $csv;
public string $date_key = 'created_at';
public array $entity_keys = [
'address1' => 'vendor.address1',
'address2' => 'vendor.address2',
'city' => 'vendor.city',
'country' => 'vendor.country_id',
'custom_value1' => 'vendor.custom_value1',
'custom_value2' => 'vendor.custom_value2',
'custom_value3' => 'vendor.custom_value3',
'custom_value4' => 'vendor.custom_value4',
'id_number' => 'vendor.id_number',
'name' => 'vendor.name',
'number' => 'vendor.number',
'phone' => 'vendor.phone',
'postal_code' => 'vendor.postal_code',
'private_notes' => 'vendor.private_notes',
'public_notes' => 'vendor.public_notes',
'state' => 'vendor.state',
'vat_number' => 'vendor.vat_number',
'website' => 'vendor.website',
'currency' => 'vendor.currency',
'first_name' => 'vendor_contact.first_name',
'last_name' => 'vendor_contact.last_name',
'contact_phone' => 'vendor_contact.phone',
'contact_custom_value1' => 'vendor_contact.custom_value1',
'contact_custom_value2' => 'vendor_contact.custom_value2',
'contact_custom_value3' => 'vendor_contact.custom_value3',
'contact_custom_value4' => 'vendor_contact.custom_value4',
'email' => 'vendor_contact.email',
'status' => 'vendor.status'
];
private array $decorate_keys = [
'vendor.country_id',
'vendor.currency',
];
public array $forced_keys = [
// 'vendor.status'
];
public function __construct(Company $company, array $input)
{
$this->company = $company;
$this->input = $input;
$this->vendor_transformer = new VendorTransformer();
$this->contact_transformer = new VendorContactTransformer();
}
public function run()
{
MultiDB::setDb($this->company->db);
App::forgetInstance('translator');
App::setLocale($this->company->locale());
$t = app('translator');
$t->replace(Ninja::transformTranslations($this->company->settings));
//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());
$query = Vendor::query()->with('contacts')
->withTrashed()
->where('company_id', $this->company->id)
->where('is_deleted', 0);
$query = $this->addDateRange($query);
$query->cursor()
->each(function ($vendor) {
$this->csv->insertOne($this->buildRow($vendor));
});
return $this->csv->toString();
}
private function buildRow(Vendor $vendor) :array
{
$transformed_contact = [];
$transformed_vendor = $this->vendor_transformer->transform($vendor);
if ($contact = $vendor->contacts()->first()) {
$transformed_contact = $this->contact_transformer->transform($contact);
}
$entity = [];
foreach (array_values($this->input['report_keys']) as $key) {
$parts = explode('.', $key);
$keyval = array_search($key, $this->entity_keys);
if (is_array($parts) && $parts[0] == 'vendor' && array_key_exists($parts[1], $transformed_vendor)) {
$entity[$keyval] = $transformed_vendor[$parts[1]];
} elseif (is_array($parts) && $parts[0] == 'vendor_contact' && array_key_exists($parts[1], $transformed_contact)) {
$entity[$keyval] = $transformed_contact[$parts[1]];
} else {
$entity[$keyval] = '';
}
}
return $this->decorateAdvancedFields($vendor, $entity);
}
private function decorateAdvancedFields(Vendor $vendor, array $entity) :array
{
if (in_array('vendor.country_id', $this->input['report_keys'])) {
$entity['country'] = $vendor->country ? ctrans("texts.country_{$vendor->country->name}") : '';
}
if (in_array('vendor.currency', $this->input['report_keys'])) {
$entity['currency'] = $vendor->currency() ? $vendor->currency()->code : $vendor->company->currency()->code;
}
$entity['status'] = $this->calculateStatus($vendor);
return $entity;
}
private function calculateStatus($vendor)
{
if ($vendor->is_deleted) {
return ctrans('texts.deleted');
}
if ($vendor->deleted_at) {
return ctrans('texts.archived');
}
return ctrans('texts.active');
}
}

View File

@ -49,7 +49,7 @@ class CreditFactory
$credit->user_id = $user_id;
$credit->company_id = $company_id;
$credit->recurring_id = null;
$credit->exchange_rate = 1;
return $credit;
}
}

View File

@ -28,7 +28,7 @@ class ExpenseFactory
$expense->tax_rate2 = 0;
$expense->tax_name3 = '';
$expense->tax_rate3 = 0;
$expense->date = null;
$expense->date = now()->format('Y-m-d');
$expense->payment_date = null;
$expense->amount = 0;
$expense->foreign_amount = 0;

View File

@ -49,7 +49,8 @@ class PurchaseOrderFactory
$purchase_order->user_id = $user_id;
$purchase_order->company_id = $company_id;
$purchase_order->recurring_id = null;
$purchase_order->exchange_rate = 1;
return $purchase_order;
}
}

View File

@ -46,6 +46,7 @@ class QuoteFactory
$quote->user_id = $user_id;
$quote->company_id = $company_id;
$quote->paid_to_date = 0;
$quote->exchange_rate = 1;
return $quote;
}

View File

@ -40,16 +40,13 @@ class RecurringExpenseToExpenseFactory
$expense->tax_name3 = $recurring_expense->tax_name3;
$expense->tax_rate3 = $recurring_expense->tax_rate3;
$expense->date = now()->format('Y-m-d');
$expense->payment_date = $recurring_expense->payment_date ?: now()->format('Y-m-d');
// $expense->payment_date = $recurring_expense->payment_date ?: now()->format('Y-m-d');
$expense->amount = $recurring_expense->amount;
$expense->foreign_amount = $recurring_expense->foreign_amount ?: 0;
//11-09-2022 - we should be tracking the recurring expense!!
$expense->recurring_expense_id = $recurring_expense->id;
// $expense->private_notes = $recurring_expense->private_notes;
// $expense->public_notes = $recurring_expense->public_notes;
$expense->public_notes = self::transformObject($recurring_expense->public_notes, $recurring_expense);
$expense->private_notes = self::transformObject($recurring_expense->private_notes, $recurring_expense);
@ -58,7 +55,7 @@ class RecurringExpenseToExpenseFactory
$expense->custom_value2 = $recurring_expense->custom_value2;
$expense->custom_value3 = $recurring_expense->custom_value3;
$expense->custom_value4 = $recurring_expense->custom_value4;
$expense->transaction_id = $recurring_expense->transaction_id;
$expense->transaction_id = null;
$expense->category_id = $recurring_expense->category_id;
$expense->payment_type_id = $recurring_expense->payment_type_id;
$expense->project_id = $recurring_expense->project_id;

View File

@ -37,7 +37,7 @@ class BankTransactionFilters extends QueryFilters
/**
* Filter based on search text.
*
* @param string query filter
* @param string $filter
* @return Builder
* @deprecated
*/
@ -118,7 +118,7 @@ class BankTransactionFilters extends QueryFilters
/**
* Sorts the list based on $sort.
*
* @param string sort formatted as column|asc
* @param string $sort formatted as column|asc
* @return Builder
*/
public function sort(string $sort = ''): Builder
@ -151,7 +151,7 @@ class BankTransactionFilters extends QueryFilters
/**
* Filters the query by the users company ID.
*
* @return Illuminate\Database\Query\Builder
* @return \Illuminate\Database\Eloquent\Builder
*/
public function entityFilter()
{

View File

@ -36,7 +36,7 @@ class BankTransactionRuleFilters extends QueryFilters
/**
* Filter based on search text.
*
* @param string query filter
* @param string $filter
* @return Builder
* @deprecated
*/
@ -54,7 +54,7 @@ class BankTransactionRuleFilters extends QueryFilters
/**
* Sorts the list based on $sort.
*
* @param string sort formatted as column|asc
* @param string $sort formatted as column|asc
* @return Builder
*/
public function sort(string $sort = ''): Builder
@ -71,7 +71,7 @@ class BankTransactionRuleFilters extends QueryFilters
/**
* Filters the query by the users company ID.
*
* @return Illuminate\Database\Query\Builder
* @return \Illuminate\Database\Eloquent\Builder
*/
public function entityFilter()
{

View File

@ -32,11 +32,13 @@ class ExpenseFilters extends QueryFilters
}
return $this->builder->where(function ($query) use ($filter) {
$query->where('public_notes', 'like', '%'.$filter.'%')
->orWhere('custom_value1', 'like', '%'.$filter.'%')
->orWhere('custom_value2', 'like', '%'.$filter.'%')
->orWhere('custom_value3', 'like', '%'.$filter.'%')
->orWhere('custom_value4', 'like', '%'.$filter.'%');
$query->where('number', 'like', '%'.$filter.'%')
->orWhere('amount', 'like', '%'.$filter.'%')
->orWhere('public_notes', 'like', '%'.$filter.'%')
->orWhere('custom_value1', 'like', '%'.$filter.'%')
->orWhere('custom_value2', 'like', '%'.$filter.'%')
->orWhere('custom_value3', 'like', '%'.$filter.'%')
->orWhere('custom_value4', 'like', '%'.$filter.'%');
});
}
@ -164,6 +166,17 @@ class ExpenseFilters extends QueryFilters
return $this->builder;
}
if ($sort_col[0] == 'client_id') {
return $this->builder->orderBy(\App\Models\Client::select('name')
->whereColumn('clients.id', 'expenses.client_id'), $sort_col[1]);
}
if ($sort_col[0] == 'vendor_id') {
return $this->builder->orderBy(\App\Models\Vendor::select('name')
->whereColumn('vendors.id', 'expenses.vendor_id'), $sort_col[1]);
}
if (is_array($sort_col) && in_array($sort_col[1], ['asc', 'desc']) && in_array($sort_col[0], ['public_notes', 'date', 'id_number', 'custom_value1', 'custom_value2', 'custom_value3', 'custom_value4'])) {
return $this->builder->orderBy($sort_col[0], $sort_col[1]);
}

View File

@ -55,6 +55,10 @@ class InvoiceFilters extends QueryFilters
$this->builder->where(function ($query) use ($status_parameters) {
$invoice_filters = [];
if (in_array('draft', $status_parameters)) {
$invoice_filters[] = Invoice::STATUS_DRAFT;
}
if (in_array('paid', $status_parameters)) {
$invoice_filters[] = Invoice::STATUS_PAID;
}
@ -131,19 +135,6 @@ class InvoiceFilters extends QueryFilters
}
/**
* @return Builder
* @throws RuntimeException
*/
public function without_deleted_clients(): Builder
{
return $this->builder->whereHas('client', function ($query) {
$query->where('is_deleted', 0);
});
}
/**
* @return Builder
* @return Builder
@ -192,6 +183,48 @@ class InvoiceFilters extends QueryFilters
->where('client_id', $this->decodePrimaryKey($client_id));
}
/**
* @param string $date
* @return Builder
* @throws InvalidArgumentException
*/
public function date(string $date = ''): Builder
{
if (strlen($date) == 0) {
return $this->builder;
}
if (is_numeric($date)) {
$date = Carbon::createFromTimestamp((int)$date);
} else {
$date = Carbon::parse($date);
}
return $this->builder->where('date', '>=', $date);
}
/**
* @param string $date
* @return Builder
* @throws InvalidArgumentException
*/
public function due_date(string $date = ''): Builder
{
if (strlen($date) == 0) {
return $this->builder;
}
if (is_numeric($date)) {
$date = Carbon::createFromTimestamp((int)$date);
} else {
$date = Carbon::parse($date);
}
return $this->builder->where('due_date', '>=', $date);
}
/**
* Sorts the list based on $sort.
*

View File

@ -120,6 +120,7 @@ class PaymentFilters extends QueryFilters
*/
public function match_transactions($value = 'true'): Builder
{
if ($value == 'true') {
return $this->builder
->where('is_deleted', 0)

View File

@ -21,7 +21,7 @@ class PaymentTermFilters extends QueryFilters
/**
* Filter based on search text.
*
* @param string query filter
* @param string $filter
* @return Builder
* @deprecated
*/
@ -39,7 +39,7 @@ class PaymentTermFilters extends QueryFilters
/**
* Sorts the list based on $sort.
*
* @param string sort formatted as column|asc
* @param string $sort formatted as column|asc
* @return Builder
*/
public function sort(string $sort = ''): Builder

View File

@ -123,6 +123,11 @@ class PurchaseOrderFilters extends QueryFilters
return $this->builder;
}
if ($sort_col[0] == 'vendor_id') {
return $this->builder->orderBy(\App\Models\Vendor::select('name')
->whereColumn('vendors.id', 'purchase_orders.vendor_id'), $sort_col[1]);
}
return $this->builder->orderBy($sort_col[0], $sort_col[1]);
}

View File

@ -11,7 +11,6 @@
namespace App\Filters;
//use Illuminate\Database\Query\Builder;
use App\Utils\Traits\MakesHash;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Http\Request;
@ -288,6 +287,31 @@ abstract class QueryFilters
return $this->builder;
}
/**
* @return Builder
*/
public function without_deleted_clients(): Builder
{
return $this->builder->where(function ($query) {
$query->whereHas('client', function ($sub_query) {
$sub_query->where('is_deleted', 0);
})->orWhere('client_id', null);
});
}
/**
* @return Builder
*/
public function without_deleted_vendors(): Builder
{
return $this->builder->where(function ($query) {
$query->whereHas('vendor', function ($sub_query) {
$sub_query->where('is_deleted', 0);
})->orWhere('vendor_id', null);
});
}
public function with(string $value = ''): Builder
{
if (strlen($value) == 0) {

View File

@ -22,7 +22,7 @@ class QuoteFilters extends QueryFilters
/**
* Filter based on search text.
*
* @param string query filter
* @param string $filter
* @return Builder
* @deprecated
*/
@ -53,7 +53,7 @@ class QuoteFilters extends QueryFilters
* - paused
* - completed
*
* @param string client_status The invoice status as seen by the client
* @param string $value The invoice status as seen by the client
* @return Builder
*/
public function client_status(string $value = ''): Builder
@ -124,7 +124,7 @@ class QuoteFilters extends QueryFilters
/**
* Sorts the list based on $sort.
*
* @param string sort formatted as column|asc
* @param string $sort formatted as column|asc
* @return Builder
*/
public function sort(string $sort = ''): Builder
@ -152,7 +152,7 @@ class QuoteFilters extends QueryFilters
/**
* Filters the query by the users company ID.
*
* @return Illuminate\Eloquent\Query\Builder
* @return \Illuminate\Database\Eloquent\Builder
*/
public function entityFilter(): Builder
{

View File

@ -21,7 +21,7 @@ class RecurringExpenseFilters extends QueryFilters
/**
* Filter based on search text.
*
* @param string query filter
* @param string $filter
* @return Builder
* @deprecated
*/
@ -52,7 +52,7 @@ class RecurringExpenseFilters extends QueryFilters
/**
* Sorts the list based on $sort.
*
* @param string sort formatted as column|asc
* @param string $sort formatted as column|asc
* @return Builder
*/
public function sort(string $sort = ''): Builder
@ -69,7 +69,7 @@ class RecurringExpenseFilters extends QueryFilters
/**
* Filters the query by the users company ID.
*
* @return Illuminate\Eloquent\Builder
* @return \Illuminate\Database\Eloquent\Builder
*/
public function entityFilter(): Builder
{

View File

@ -21,7 +21,7 @@ class SubscriptionFilters extends QueryFilters
/**
* Filter based on search text.
*
* @param string query filter
* @param string $filter
* @return Builder
* @deprecated
*/
@ -39,7 +39,7 @@ class SubscriptionFilters extends QueryFilters
/**
* Sorts the list based on $sort.
*
* @param string sort formatted as column|asc
* @param string $sort formatted as column|asc
* @return Builder
*/
public function sort(string $sort = ''): Builder

View File

@ -48,7 +48,7 @@ class SystemLogFilters extends QueryFilters
/**
* Filter based on search text.
*
* @param string query filter
* @param string $filter
* @return Builder
* @deprecated
*/
@ -64,7 +64,7 @@ class SystemLogFilters extends QueryFilters
/**
* Sorts the list based on $sort.
*
* @param string sort formatted as column|asc
* @param string $sort formatted as column|asc
* @return Builder
*/
public function sort(string $sort = ''): Builder

View File

@ -24,7 +24,7 @@ class TaskFilters extends QueryFilters
/**
* Filter based on search text.
*
* @param string query filter
* @param string $filter
* @return Builder
* @deprecated
*/
@ -56,7 +56,7 @@ class TaskFilters extends QueryFilters
* - all
* - invoiced
*
* @param string client_status The invoice status as seen by the client
* @param string $value The invoice status as seen by the client
* @return Builder
*/
public function client_status(string $value = ''): Builder
@ -99,7 +99,7 @@ class TaskFilters extends QueryFilters
/**
* Sorts the list based on $sort.
*
* @param string sort formatted as column|asc
* @param string $sort formatted as column|asc
* @return Builder
*/
public function sort(string $sort = ''): Builder
@ -123,6 +123,21 @@ class TaskFilters extends QueryFilters
return $this->builder->orderBy($sort_col[0], $sort_col[1]);
}
public function task_status(string $value = ''): Builder
{
if (strlen($value) == 0) {
return $this->builder;
}
$status_parameters = explode(',', $value);
if(count($status_parameters) >= 1)
$this->builder->whereIn('status_id', $this->transformKeys($status_parameters));
return $this->builder;
}
/**
* Filters the query by the users company ID.
*

View File

@ -21,7 +21,7 @@ class TaskStatusFilters extends QueryFilters
/**
* Filter based on search text.
*
* @param string query filter
* @param string $filter
* @return Builder
* @deprecated
*/
@ -39,7 +39,7 @@ class TaskStatusFilters extends QueryFilters
/**
* Sorts the list based on $sort.
*
* @param string sort formatted as column|asc
* @param string $sort formatted as column|asc
* @return Builder
*/
public function sort(string $sort = ''): Builder

View File

@ -21,7 +21,7 @@ class TaxRateFilters extends QueryFilters
/**
* Filter based on search text.
*
* @param string query filter
* @param string $filter
* @return Builder
* @deprecated
*/
@ -39,7 +39,7 @@ class TaxRateFilters extends QueryFilters
/**
* Sorts the list based on $sort.
*
* @param string sort formatted as column|asc
* @param string $sort formatted as column|asc
* @return Builder
*/
public function sort(string $sort = ''): Builder

View File

@ -21,7 +21,7 @@ class TokenFilters extends QueryFilters
/**
* Filter based on search text.
*
* @param string query filter
* @param string $filter
* @return Builder
* @deprecated
*/
@ -36,10 +36,16 @@ class TokenFilters extends QueryFilters
});
}
public function is_system(string $value = 'false'): Builder
{
return $this->builder->where('is_system', $value == 'false' ? false : true);
}
/**
* Sorts the list based on $sort.
*
* @param string sort formatted as column|asc
* @param string $sort formatted as column|asc
* @return Builder
*/
public function sort(string $sort = ''): Builder

View File

@ -21,7 +21,7 @@ class UserFilters extends QueryFilters
/**
* Filter based on search text.
*
* @param string query filter
* @param string $filter
* @return Builder
* @deprecated
*/
@ -43,7 +43,7 @@ class UserFilters extends QueryFilters
/**
* Sorts the list based on $sort.
*
* @param string sort formatted as column|asc
* @param string $sort formatted as column|asc
* @return Builder
*/
public function sort(string $sort = ''): Builder
@ -69,6 +69,19 @@ class UserFilters extends QueryFilters
});
}
/**
* Filters users that have been removed from the
* company, but not deleted from the system.
*
* @return void
*/
public function hideRemovedUsers()
{
return $this->builder->whereHas('company_users', function ($q) {
$q->where('company_id', '=', auth()->user()->company()->id)->whereNull('deleted_at');
});
}
/**
* Overrides the base with() function as no company ID
* exists on the user table

View File

@ -21,7 +21,7 @@ class VendorFilters extends QueryFilters
/**
* Filter based on search text.
*
* @param string query filter
* @param string $filter
* @return Builder
* @deprecated
*/
@ -58,7 +58,7 @@ class VendorFilters extends QueryFilters
/**
* Sorts the list based on $sort.
*
* @param string sort formatted as column|asc
* @param string $sort formatted as column|asc
* @return Builder
*/
public function sort(string $sort = ''): Builder

View File

@ -21,7 +21,7 @@ class WebhookFilters extends QueryFilters
/**
* Filter based on search text.
*
* @param string query filter
* @param string $filter
* @return Builder
* @deprecated
*/
@ -39,7 +39,7 @@ class WebhookFilters extends QueryFilters
/**
* Sorts the list based on $sort.
*
* @param string sort formatted as column|asc
* @param string $sort formatted as column|asc
* @return Builder
*/
public function sort(string $sort = ''): Builder

View File

@ -81,6 +81,19 @@ class AccountTransformer implements AccountTransformerInterface
public function transformAccount($account)
{
$current_balance = 0;
$account_currency = '';
if(property_exists($account, 'currentBalance')) {
$current_balance = $account->currentBalance->amount ?? 0;
$account_currency = $account->currentBalance->currency ?? '';
}
elseif(property_exists($account, 'balance')){
$current_balance = $account->balance->amount ?? 0;
$account_currency = $account->balance->currency ?? '';
}
return [
'id' => $account->id,
'account_type' => $account->CONTAINER,
@ -92,8 +105,8 @@ class AccountTransformer implements AccountTransformerInterface
'provider_id' => $account->providerId,
'provider_name' => $account->providerName,
'nickname' => property_exists($account, 'nickname') ? $account->nickname : '',
'current_balance' => property_exists($account, 'currentBalance') ? $account->currentBalance->amount : 0,
'account_currency' => property_exists($account, 'currency') ? $account->currentBalance->currency : '',
'current_balance' => $current_balance,
'account_currency' => $account_currency,
];
}
}

View File

@ -185,6 +185,21 @@ class Yodlee
}
}
public function getAccountSummary($account_id)
{
$token = $this->getAccessToken();
$response = Http::withHeaders($this->getHeaders(["Authorization" => "Bearer {$token}"]))->get($this->getEndpoint(). "/accounts/{$account_id}", []);
if ($response->successful()) {
return $response->object();
}
if ($response->failed()) {
return false;
}
}
public function deleteAccount($account_id)
{
$token = $this->getAccessToken();

View File

@ -19,7 +19,7 @@ use Illuminate\View\View;
*
* @param $page
* @param bool $boolean
* @return bool
* @return bool | string
*/
function isActive($page, bool $boolean = false)
{
@ -40,8 +40,6 @@ function isActive($page, bool $boolean = false)
return true;
}
return false;
}

View File

@ -53,9 +53,8 @@ class EpcQrGenerator
$qr = $writer->writeString($this->encodeMessage(), 'utf-8');
} catch(\Throwable $e) {
return '';
} catch(\Exception $e) {
return '';
}
}
return "<svg viewBox='0 0 200 200' width='200' height='200' x='0' y='0' xmlns='http://www.w3.org/2000/svg'>
<rect x='0' y='0' width='100%'' height='100%' />{$qr}</svg>";
}

View File

@ -238,14 +238,20 @@ class InvoiceItemSum
{
$this->rule->tax($this->item);
$precision = strlen(substr(strrchr($this->rule->tax_rate1, "."), 1));
$this->item->tax_name1 = $this->rule->tax_name1;
$this->item->tax_rate1 = $this->rule->tax_rate1;
$this->item->tax_rate1 = round($this->rule->tax_rate1, $precision);
$precision = strlen(substr(strrchr($this->rule->tax_rate2, "."), 1));
$this->item->tax_name2 = $this->rule->tax_name2;
$this->item->tax_rate2 = $this->rule->tax_rate2;
$this->item->tax_rate2 = round($this->rule->tax_rate2, $precision);
$precision = strlen(substr(strrchr($this->rule->tax_rate3, "."), 1));
$this->item->tax_name3 = $this->rule->tax_name3;
$this->item->tax_rate3 = $this->rule->tax_rate3;
$this->item->tax_rate3 = round($this->rule->tax_rate3, $precision);
return $this;
}

View File

@ -12,11 +12,13 @@
namespace App\Helpers\Invoice;
use App\Models\Quote;
use App\Models\Client;
use App\Models\Credit;
use App\Models\Invoice;
use App\Models\PurchaseOrder;
use App\Models\RecurringQuote;
use App\Models\RecurringInvoice;
use App\DataMapper\Tax\RuleInterface;
use App\Utils\Traits\NumberFormatter;
class InvoiceItemSumInclusive
@ -25,6 +27,71 @@ class InvoiceItemSumInclusive
use Discounter;
use Taxer;
private array $eu_tax_jurisdictions = [
'AT', // Austria
'BE', // Belgium
'BG', // Bulgaria
'CY', // Cyprus
'CZ', // Czech Republic
'DE', // Germany
'DK', // Denmark
'EE', // Estonia
'ES', // Spain
'FI', // Finland
'FR', // France
'GR', // Greece
'HR', // Croatia
'HU', // Hungary
'IE', // Ireland
'IT', // Italy
'LT', // Lithuania
'LU', // Luxembourg
'LV', // Latvia
'MT', // Malta
'NL', // Netherlands
'PL', // Poland
'PT', // Portugal
'RO', // Romania
'SE', // Sweden
'SI', // Slovenia
'SK', // Slovakia
];
private array $tax_jurisdictions = [
'AT', // Austria
'BE', // Belgium
'BG', // Bulgaria
'CY', // Cyprus
'CZ', // Czech Republic
'DE', // Germany
'DK', // Denmark
'EE', // Estonia
'ES', // Spain
'FI', // Finland
'FR', // France
'GR', // Greece
'HR', // Croatia
'HU', // Hungary
'IE', // Ireland
'IT', // Italy
'LT', // Lithuania
'LU', // Luxembourg
'LV', // Latvia
'MT', // Malta
'NL', // Netherlands
'PL', // Poland
'PT', // Portugal
'RO', // Romania
'SE', // Sweden
'SI', // Slovenia
'SK', // Slovakia
'US', // USA
'AU', // Australia
];
protected RecurringInvoice | Invoice | Quote | Credit | PurchaseOrder | RecurringQuote $invoice;
private $currency;
@ -39,6 +106,12 @@ class InvoiceItemSumInclusive
private $tax_collection;
private bool $calc_tax = false;
private ?Client $client;
private RuleInterface $rule;
public function __construct(RecurringInvoice | Invoice | Quote | Credit | PurchaseOrder | RecurringQuote $invoice)
{
$this->tax_collection = collect([]);
@ -47,6 +120,8 @@ class InvoiceItemSumInclusive
if ($this->invoice->client) {
$this->currency = $this->invoice->client->currency();
$this->client = $this->invoice->client;
$this->shouldCalculateTax();
} else {
$this->currency = $this->invoice->vendor->currency();
}
@ -107,12 +182,46 @@ class InvoiceItemSumInclusive
return $this;
}
/**
* Attempts to calculate taxes based on the clients location
*
* @return self
*/
private function calcTaxesAutomatically(): self
{
$this->rule->tax($this->item);
$precision = strlen(substr(strrchr($this->rule->tax_rate1, "."), 1));
$this->item->tax_name1 = $this->rule->tax_name1;
$this->item->tax_rate1 = round($this->rule->tax_rate1, $precision);
$precision = strlen(substr(strrchr($this->rule->tax_rate2, "."), 1));
$this->item->tax_name2 = $this->rule->tax_name2;
$this->item->tax_rate2 = round($this->rule->tax_rate2, $precision);
$precision = strlen(substr(strrchr($this->rule->tax_rate3, "."), 1));
$this->item->tax_name3 = $this->rule->tax_name3;
$this->item->tax_rate3 = round($this->rule->tax_rate3, $precision);
return $this;
}
/**
* Taxes effect the line totals and item costs. we decrement both on
* application of inclusive tax rates.
*/
private function calcTaxes()
{
if ($this->calc_tax) {
$this->calcTaxesAutomatically();
}
$item_tax = 0;
$amount = $this->item->line_total - ($this->item->line_total * ($this->invoice->discount / 100));
@ -121,7 +230,6 @@ class InvoiceItemSumInclusive
$item_tax += $this->formatValue($item_tax_rate1_total, $this->currency->precision);
// if($item_tax_rate1_total != 0)
if (strlen($this->item->tax_name1) > 1) {
$this->groupTax($this->item->tax_name1, $this->item->tax_rate1, $item_tax_rate1_total);
}
@ -275,4 +383,36 @@ class InvoiceItemSumInclusive
$this->setTotalTaxes($item_tax);
}
private function shouldCalculateTax(): self
{
if (!$this->invoice->company?->calculate_taxes || $this->invoice->company->account->isFreeHostedClient()) {
$this->calc_tax = false;
return $this;
}
if (in_array($this->client->company->country()->iso_3166_2, $this->tax_jurisdictions) ) { //only calculate for supported tax jurisdictions
$class = "App\DataMapper\Tax\\".$this->client->company->country()->iso_3166_2."\\Rule";
$this->rule = new $class();
if($this->rule->regionWithNoTaxCoverage($this->client->country->iso_3166_2))
return $this;
$this->rule
->setEntity($this->invoice)
->init();
$this->calc_tax = $this->rule->shouldCalcTax();
return $this;
}
return $this;
}
}

View File

@ -69,6 +69,7 @@ class ProRata
return [];
}
/** @var \App\Models\RecurringInvoice $recurring_invoice **/
$recurring_invoice = RecurringInvoice::find($invoice->recurring_id)->first();
if (! $recurring_invoice) {
@ -110,13 +111,13 @@ class ProRata
case RecurringInvoice::FREQUENCY_MONTHLY:
return now()->diffInDays(now()->addMonthNoOverflow());
case RecurringInvoice::FREQUENCY_TWO_MONTHS:
return now()->diffInDays(now()->addMonthNoOverflow(2));
return now()->diffInDays(now()->addMonthsNoOverflow(2));
case RecurringInvoice::FREQUENCY_THREE_MONTHS:
return now()->diffInDays(now()->addMonthNoOverflow(3));
return now()->diffInDays(now()->addMonthsNoOverflow(3));
case RecurringInvoice::FREQUENCY_FOUR_MONTHS:
return now()->diffInDays(now()->addMonthNoOverflow(4));
return now()->diffInDays(now()->addMonthsNoOverflow(4));
case RecurringInvoice::FREQUENCY_SIX_MONTHS:
return now()->diffInDays(now()->addMonthNoOverflow(6));
return now()->diffInDays(now()->addMonthsNoOverflow(6));
case RecurringInvoice::FREQUENCY_ANNUALLY:
return now()->diffInDays(now()->addYear());
case RecurringInvoice::FREQUENCY_TWO_YEARS:

View File

@ -64,6 +64,7 @@ class SubscriptionCalculator
}
if ($refund_invoice) {
/** @var \App\Models\Subscription $subscription **/
$subscription = Subscription::find($this->invoice->subscription_id);
$pro_rata = new ProRata;

View File

@ -11,24 +11,23 @@
namespace App\Http\Controllers;
use App\Http\Requests\Activity\DownloadHistoricalEntityRequest;
use App\Models\Activity;
use App\Transformers\ActivityTransformer;
use App\Utils\HostedPDF\NinjaPdf;
use App\Utils\Ninja;
use App\Utils\PhantomJS\Phantom;
use App\Utils\Traits\Pdf\PageNumbering;
use App\Utils\Traits\Pdf\PdfMaker;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
use Illuminate\Support\Facades\Storage;
use stdClass;
use Symfony\Component\HttpFoundation\StreamedResponse;
use App\Utils\Ninja;
use App\Models\Activity;
use Illuminate\Http\Request;
use App\Utils\Traits\MakesHash;
use App\Utils\PhantomJS\Phantom;
use App\Utils\HostedPDF\NinjaPdf;
use App\Utils\Traits\Pdf\PdfMaker;
use App\Utils\Traits\Pdf\PageNumbering;
use Illuminate\Support\Facades\Storage;
use App\Transformers\ActivityTransformer;
use App\Http\Requests\Activity\ShowActivityRequest;
use App\Http\Requests\Activity\DownloadHistoricalEntityRequest;
class ActivityController extends BaseController
{
use PdfMaker, PageNumbering;
use PdfMaker, PageNumbering, MakesHash;
protected $entity_type = Activity::class;
@ -39,50 +38,6 @@ class ActivityController extends BaseController
parent::__construct();
}
/**
* @OA\Get(
* path="/api/v1/activities",
* operationId="getActivities",
* tags={"actvities"},
* summary="Gets a list of actvities",
* description="Lists all activities",
* @OA\Parameter(ref="#/components/parameters/X-API-TOKEN"),
* @OA\Parameter(ref="#/components/parameters/X-Requested-With"),
* @OA\Parameter(ref="#/components/parameters/include"),
* @OA\Parameter(ref="#/components/parameters/index"),
* @OA\Parameter(
* name="rows",
* in="query",
* description="The number of activities to return",
* example="50",
* required=false,
* @OA\Schema(
* type="number",
* format="integer",
* ),
* ),
* @OA\Response(
* response=200,
* description="A list of actvities",
* @OA\Header(header="X-MINIMUM-CLIENT-VERSION", ref="#/components/headers/X-MINIMUM-CLIENT-VERSION"),
* @OA\Header(header="X-RateLimit-Remaining", ref="#/components/headers/X-RateLimit-Remaining"),
* @OA\Header(header="X-RateLimit-Limit", ref="#/components/headers/X-RateLimit-Limit"),
* @OA\JsonContent(ref="#/components/schemas/Activity"),
* ),
* @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"),
* ),
* )
* @param Request $request
* @return Response|mixed
*/
public function index(Request $request)
{
$default_activities = $request->has('rows') ? $request->input('rows') : 75;
@ -91,47 +46,7 @@ class ActivityController extends BaseController
->orderBy('created_at', 'DESC')
->company()
->take($default_activities);
// if ($request->has('react')) {
// /** @var \App\Models\User auth()->user() */
// $user = auth()->user();
// if (!$user->isAdmin()) {
// $activities->where('user_id', auth()->user()->id);
// }
// $system = ctrans('texts.system');
// $data = $activities->cursor()->map(function ($activity) {
// $arr =
// [
// 'client' => $activity->client ? $activity->client : '',
// 'contact' => $activity->client ? $activity->contact : '',
// 'quote' => $activity->quote ? $activity->quote : '',
// 'user' => $activity->user ? $activity->user : '',
// 'expense' => $activity->expense ? $activity->expense : '',
// 'invoice' => $activity->invoice ? $activity->invoice : '',
// 'recurring_invoice' => $activity->recurring_invoice ? $activity->recurring_invoice : '',
// 'payment' => $activity->payment ? $activity->payment : '',
// 'credit' => $activity->credit ? $activity->credit : '',
// 'task' => $activity->task ? $activity->task : '',
// 'vendor' => $activity->vendor ? $activity->vendor : '',
// 'purchase_order' => $activity->purchase_order ? $activity->purchase_order : '',
// 'subscription' => $activity->subscription ? $activity->subscription : '',
// 'vendor_contact' => $activity->vendor_contact ? $activity->vendor_contact : '',
// 'recurring_expense' => $activity->recurring_expense ? $activity->recurring_expense : '',
// ];
// $activity_array = $activity->toArray();
// return array_merge($arr, $activity_array);
// });
// return response()->json(['data' => $data->toArray()], 200);
// }
// else
if($request->has('reactv2')) {
/** @var \App\Models\User auth()->user() */
@ -143,7 +58,7 @@ class ActivityController extends BaseController
$system = ctrans('texts.system');
$data = $activities->cursor()->map(function ($activity) use ($system) {
$data = $activities->cursor()->map(function ($activity) {
return $activity->activity_string();
@ -155,47 +70,36 @@ class ActivityController extends BaseController
return $this->listResponse($activities);
}
/**
* @OA\Get(
* path="/api/v1/actvities/download_entity/{activity_id}",
* operationId="getActivityHistoricalEntityPdf",
* tags={"actvities"},
* summary="Gets a PDF for the given activity",
* description="Gets a PDF for the given activity",
* @OA\Parameter(ref="#/components/parameters/X-API-TOKEN"),
* @OA\Parameter(ref="#/components/parameters/X-Requested-With"),
* @OA\Parameter(
* name="activity_id",
* in="path",
* description="The Activity Hashed ID",
* example="D2J234DFA",
* required=true,
* @OA\Schema(
* type="string",
* format="string",
* ),
* ),
* @OA\Response(
* response=200,
* description="PDF File",
* @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=404,
* description="No file exists for the given record",
* ),
* @OA\Response(
* response="default",
* description="Unexpected Error",
* @OA\JsonContent(ref="#/components/schemas/Error"),
* ),
* )
* @param DownloadHistoricalEntityRequest $request
* @param Activity $activity
* @return JsonResponse|StreamedResponse
*/
public function entityActivity(ShowActivityRequest $request)
{
$default_activities = request()->has('rows') ? request()->input('rows') : 75;
$activities = Activity::with('user')
->orderBy('created_at', 'DESC')
->company()
->where("{$request->entity}_id", $request->entity_id)
->take($default_activities);
/** @var \App\Models\User auth()->user() */
$user = auth()->user();
if (!$user->isAdmin()) {
$activities->where('user_id', auth()->user()->id);
}
$system = ctrans('texts.system');
$data = $activities->cursor()->map(function ($activity) {
return $activity->activity_string();
});
return response()->json(['data' => $data->toArray()], 200);
}
public function downloadHistoricalEntity(DownloadHistoricalEntityRequest $request, Activity $activity)
{
$backup = $activity->backup;
@ -244,6 +148,8 @@ class ActivityController extends BaseController
}
}
$activity->company->setLocale();
if (isset($activity->invoice_id)) {
$filename = $activity->invoice->numberFormatter().'.pdf';
} elseif (isset($activity->quote_id)) {

View File

@ -62,11 +62,15 @@ class ContactForgotPasswordController extends Controller
if (Ninja::isHosted() && $request->session()->has('company_key')) {
MultiDB::findAndSetDbByCompanyKey($request->session()->get('company_key'));
/** @var \App\Models\Company $company **/
$company = Company::where('company_key', $request->session()->get('company_key'))->first();
$account = $company->account;
}
if (! $account) {
/** @var \App\Models\Account $account **/
$account = Account::first();
$company = $account->companies->first();
}
@ -97,7 +101,11 @@ class ContactForgotPasswordController extends Controller
$this->validateEmail($request);
if (Ninja::isHosted() && $company = Company::where('company_key', $request->input('company_key'))->first()) {
/** @var \App\Models\Company $company **/
/** @var \App\Models\ClientContact $contact **/
$contact = ClientContact::where(['email' => $request->input('email'), 'company_id' => $company->id])
->whereHas('client', function ($query) {
$query->where('is_deleted', 0);

View File

@ -52,6 +52,7 @@ class ContactLoginController extends Controller
$company = Company::where('company_key', $company_key)->first();
}
/** @var \App\Models\Company $company **/
if ($company) {
$account = $company->account;
} elseif (! $company && strpos($request->getHost(), 'invoicing.co') !== false) {
@ -63,6 +64,7 @@ class ContactLoginController extends Controller
$company = Company::where('portal_domain', $request->getSchemeAndHttpHost())->first();
} elseif (Ninja::isSelfHost()) {
/** @var \App\Models\Account $account **/
$account = Account::first();
$company = $account->default_company;
} else {
@ -97,6 +99,7 @@ class ContactLoginController extends Controller
}
if (Ninja::isHosted() && $request->has('password') && $company = Company::where('company_key', $request->input('company_key'))->first()) {
/** @var \App\Models\Company $company **/
$contact = ClientContact::where(['email' => $request->input('email'), 'company_id' => $company->id])
->whereHas('client', function ($query) {
$query->where('is_deleted', 0);

View File

@ -39,7 +39,8 @@ class ContactRegisterController extends Controller
} else {
$key = request()->session()->has('company_key') ? request()->session()->get('company_key') : $company_key;
}
/** @var \App\Models\Company $company **/
$company = Company::where('company_key', $key)->firstOrFail();
App::forgetInstance('translator');

View File

@ -71,6 +71,8 @@ class ContactResetPasswordController extends Controller
{
if ($request->session()->has('company_key')) {
MultiDB::findAndSetDbByCompanyKey($request->session()->get('company_key'));
/** @var \App\Models\Company $company **/
$company = Company::where('company_key', $request->session()->get('company_key'))->first();
$db = $company->db;
$account = $company->account;
@ -79,10 +81,12 @@ class ContactResetPasswordController extends Controller
if ($account_key) {
MultiDB::findAndSetDbByAccountKey($account_key);
/** @var \App\Models\Account $account **/
$account = Account::where('key', $account_key)->first();
$db = $account->companies->first()->db;
$company = $account->companies->first();
} else {
/** @var \App\Models\Account $account **/
$account = Account::first();
$db = $account->companies->first()->db;
$company = $account->companies->first();

View File

@ -82,6 +82,7 @@ class ForgotPasswordController extends Controller
{
if ($request->has('company_key')) {
MultiDB::findAndSetDbByCompanyKey($request->input('company_key'));
/** @var \App\Models\Company $company **/
$company = Company::where('company_key', $request->input('company_key'))->first();
$account = $company->account;
} else {

View File

@ -60,6 +60,7 @@ class ResetPasswordController extends Controller
if (Ninja::isHosted()) {
MultiDB::findAndSetDbByCompanyKey($request->session()->get('company_key'));
/** @var \App\Models\Company $company **/
$company = Company::where('company_key', $request->session()->get('company_key'))->first();
}

View File

@ -12,6 +12,7 @@
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
use App\Models\BankIntegration;
use App\Utils\Traits\MakesHash;
use Illuminate\Http\JsonResponse;
@ -50,7 +51,7 @@ class BankIntegrationController extends BaseController
/**
* @param BankIntegrationFilters $filters
* @return Responsec
* @return Response
*/
public function index(BankIntegrationFilters $filters)
{
@ -209,7 +210,12 @@ class BankIntegrationController extends BaseController
$accounts = $yodlee->getAccounts();
foreach ($accounts as $account) {
if (!BankIntegration::withTrashed()->where('bank_account_id', $account['id'])->where('company_id', $user->company()->id)->exists()) {
if ($bi = BankIntegration::withTrashed()->where('bank_account_id', $account['id'])->where('company_id', $user->company()->id)->first()){
$bi->balance = $account['current_balance'];
$bi->currency = $account['account_currency'];
$bi->save();
}
else {
$bank_integration = new BankIntegration();
$bank_integration->company_id = $user->company()->id;
$bank_integration->account_id = $user->account_id;
@ -245,7 +251,7 @@ class BankIntegrationController extends BaseController
* Return the remote list of accounts stored on the third party provider
* and update our local cache.
*
* @return Response
* @return Response | JsonResponse
*
*/

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