mirror of
				https://github.com/invoiceninja/invoiceninja.git
				synced 2025-10-31 17:27:33 -04:00 
			
		
		
		
	Merge remote-tracking branch 'origin/v5-develop' into v5-develop
This commit is contained in:
		
						commit
						c908819348
					
				
							
								
								
									
										41
									
								
								.github/ISSUE_TEMPLATE/bug_report.md
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								.github/ISSUE_TEMPLATE/bug_report.md
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,41 @@ | |||||||
|  | --- | ||||||
|  | name: Bug report | ||||||
|  | about: Create a report to help us improve | ||||||
|  | title: '' | ||||||
|  | labels: triage | ||||||
|  | assignees: '' | ||||||
|  | 
 | ||||||
|  | --- | ||||||
|  | 
 | ||||||
|  | **What version of Invoice Ninja are you running? ie v4.5.25 / v5.0.30** | ||||||
|  | 
 | ||||||
|  | **What environment are you running?** | ||||||
|  | Docker | ||||||
|  | Shared Hosting | ||||||
|  | ZIP | ||||||
|  | Other | ||||||
|  | 
 | ||||||
|  | **Have you checked log files (storage/logs/) Please provide redacted output** | ||||||
|  | 
 | ||||||
|  | **Have you searched existing issues?** | ||||||
|  | 
 | ||||||
|  | **Have you reported this to Slack/forum before posting?** | ||||||
|  | 
 | ||||||
|  | **Describe the bug** | ||||||
|  | A clear and concise description of what the bug is. | ||||||
|  | 
 | ||||||
|  | **Steps To Reproduce** | ||||||
|  | Please list the steps to reproduce the issue | ||||||
|  | 
 | ||||||
|  | **Expected behavior** | ||||||
|  | A clear and concise description of what you expected to happen. | ||||||
|  | 
 | ||||||
|  | **Screenshots** | ||||||
|  | If applicable, add screenshots to help explain your problem. | ||||||
|  | 
 | ||||||
|  | **Additional context** | ||||||
|  | Add any other context about the problem here. | ||||||
|  | 
 | ||||||
|  | <!-- Note: Before posting don't forget to check our "Troubleshooting" category in the [docs](https://invoiceninja.github.io/docs/self-host-troubleshooting/) (https://invoiceninja.github.io/docs/self-host-troubleshooting/) --> | ||||||
|  | 
 | ||||||
|  | **(v5) Can you replicate the issue on our demo site? https://demo.invoiceninja.com** | ||||||
							
								
								
									
										24
									
								
								.github/ISSUE_TEMPLATE/feature_request.md
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								.github/ISSUE_TEMPLATE/feature_request.md
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,24 @@ | |||||||
|  | --- | ||||||
|  | name: Feature request | ||||||
|  | about: Suggest an idea for this project | ||||||
|  | title: '' | ||||||
|  | labels: feature request | ||||||
|  | assignees: '' | ||||||
|  | 
 | ||||||
|  | --- | ||||||
|  | 
 | ||||||
|  | **What version of Invoice Ninja are you running? ie v4.5 / v5** | ||||||
|  | 
 | ||||||
|  | **What environment are you running?** | ||||||
|  | Docker | ||||||
|  | Shared Hosting | ||||||
|  | ZIP | ||||||
|  | Other | ||||||
|  | 
 | ||||||
|  | **Have you searched existing issues/requests?** | ||||||
|  | 
 | ||||||
|  | **Screenshots** | ||||||
|  | If applicable, add screenshots to help explain your request/question. | ||||||
|  | 
 | ||||||
|  | **Additional context** | ||||||
|  | Add any other context about the request/question here. | ||||||
| @ -1 +1 @@ | |||||||
| 5.5.48 | 5.5.55 | ||||||
| @ -119,6 +119,7 @@ class CheckData extends Command | |||||||
|         $this->checkDuplicateRecurringInvoices(); |         $this->checkDuplicateRecurringInvoices(); | ||||||
|         $this->checkOauthSanity(); |         $this->checkOauthSanity(); | ||||||
|         $this->checkVendorSettings(); |         $this->checkVendorSettings(); | ||||||
|  |         $this->checkClientSettings(); | ||||||
|          |          | ||||||
|         if(Ninja::isHosted()){ |         if(Ninja::isHosted()){ | ||||||
|             $this->checkAccountStatuses(); |             $this->checkAccountStatuses(); | ||||||
| @ -952,24 +953,24 @@ class CheckData extends Command | |||||||
| 
 | 
 | ||||||
|         if ($this->option('fix') == 'true') { |         if ($this->option('fix') == 'true') { | ||||||
| 
 | 
 | ||||||
|             Client::query()->whereNull('settings->currency_id')->cursor()->each(function ($client){ |             // Client::query()->whereNull('settings->currency_id')->cursor()->each(function ($client){
 | ||||||
| 
 | 
 | ||||||
|                 if(is_array($client->settings) && count($client->settings) == 0) |             //     if(is_array($client->settings) && count($client->settings) == 0)
 | ||||||
|                 { |             //     {
 | ||||||
|                     $settings = ClientSettings::defaults(); |             //         $settings = ClientSettings::defaults();
 | ||||||
|                     $settings->currency_id = $client->company->settings->currency_id; |             //         $settings->currency_id = $client->company->settings->currency_id;
 | ||||||
|                 } |             //     }
 | ||||||
|                 else { |             //     else {
 | ||||||
|                     $settings = $client->settings; |             //         $settings = $client->settings;
 | ||||||
|                     $settings->currency_id = $client->company->settings->currency_id; |             //         $settings->currency_id = $client->company->settings->currency_id;
 | ||||||
|                 } |             //     }
 | ||||||
| 
 | 
 | ||||||
|                 $client->settings = $settings; |             //     $client->settings = $settings;
 | ||||||
|                 $client->save(); |             //     $client->save();
 | ||||||
| 
 | 
 | ||||||
|                 $this->logMessage("Fixing currency for # {$client->id}"); |             //     $this->logMessage("Fixing currency for # {$client->id}");
 | ||||||
| 
 | 
 | ||||||
|             }); |             // });
 | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|             Client::query()->whereNull('country_id')->cursor()->each(function ($client){ |             Client::query()->whereNull('country_id')->cursor()->each(function ($client){ | ||||||
|  | |||||||
| @ -306,8 +306,8 @@ class CreateSingleAccount extends Command | |||||||
| 
 | 
 | ||||||
|         $webhook_config = [ |         $webhook_config = [ | ||||||
|             'post_purchase_url' => 'http://ninja.test:8000/api/admin/plan', |             'post_purchase_url' => 'http://ninja.test:8000/api/admin/plan', | ||||||
|             'post_purchase_rest_method' => 'POST', |             'post_purchase_rest_method' => 'post', | ||||||
|             'post_purchase_headers' => [], |             'post_purchase_headers' => [config('ninja.ninja_hosted_header') => config('ninja.ninja_hosted_secret')], | ||||||
|         ]; |         ]; | ||||||
| 
 | 
 | ||||||
|         $sub = SubscriptionFactory::create($company->id, $user->id); |         $sub = SubscriptionFactory::create($company->id, $user->id); | ||||||
|  | |||||||
| @ -437,7 +437,7 @@ class CreateTestData extends Command | |||||||
|             'company_id' => $client->company->id, |             'company_id' => $client->company->id, | ||||||
|         ]); |         ]); | ||||||
| 
 | 
 | ||||||
|         Document::factory()->count(5)->create([ |         Document::factory()->count(1)->create([ | ||||||
|             'user_id' => $client->user->id, |             'user_id' => $client->user->id, | ||||||
|             'company_id' => $client->company_id, |             'company_id' => $client->company_id, | ||||||
|             'documentable_type' => Vendor::class, |             'documentable_type' => Vendor::class, | ||||||
|  | |||||||
| @ -56,7 +56,7 @@ class ReactBuilder extends Command | |||||||
|         $directoryIterator = new \RecursiveDirectoryIterator(public_path('react'), \RecursiveDirectoryIterator::SKIP_DOTS); |         $directoryIterator = new \RecursiveDirectoryIterator(public_path('react'), \RecursiveDirectoryIterator::SKIP_DOTS); | ||||||
| 
 | 
 | ||||||
|         foreach (new \RecursiveIteratorIterator($directoryIterator) as $file) { |         foreach (new \RecursiveIteratorIterator($directoryIterator) as $file) { | ||||||
|             if (str_contains($file->getFileName(), '.js')) { |             if (str_contains($file->getFileName(), '.js') && !strpos($file->getFileName(), '.json')) { | ||||||
|                 if (str_contains($file->getFileName(), 'index.')) { |                 if (str_contains($file->getFileName(), 'index.')) { | ||||||
|                     $includes .= '<script type="module" crossorigin src="/react/'.$file->getFileName().'"></script>'."\n"; |                     $includes .= '<script type="module" crossorigin src="/react/'.$file->getFileName().'"></script>'."\n"; | ||||||
|                 } else { |                 } else { | ||||||
|  | |||||||
| @ -27,7 +27,7 @@ class TranslationsExport extends Command | |||||||
|      * |      * | ||||||
|      * @var string |      * @var string | ||||||
|      */ |      */ | ||||||
|     protected $signature = 'ninja:translations'; |     protected $signature = 'ninja:translations {--type=} {--path=}'; | ||||||
| 
 | 
 | ||||||
|     /** |     /** | ||||||
|      * The console command description. |      * The console command description. | ||||||
| @ -36,8 +36,11 @@ class TranslationsExport extends Command | |||||||
|      */ |      */ | ||||||
|     protected $description = 'Transform translations to json'; |     protected $description = 'Transform translations to json'; | ||||||
| 
 | 
 | ||||||
|  |     protected $log = ''; | ||||||
|  | 
 | ||||||
|     private array $langs = [ |     private array $langs = [ | ||||||
|         'ar', |         'ar', | ||||||
|  |         'bg', | ||||||
|         'ca', |         'ca', | ||||||
|         'cs', |         'cs', | ||||||
|         'da', |         'da', | ||||||
| @ -47,10 +50,12 @@ class TranslationsExport extends Command | |||||||
|         'en_GB', |         'en_GB', | ||||||
|         'es', |         'es', | ||||||
|         'es_ES', |         'es_ES', | ||||||
|  |         'et', | ||||||
|         'fa', |         'fa', | ||||||
|         'fi', |         'fi', | ||||||
|         'fr', |         'fr', | ||||||
|         'fr_CA', |         'fr_CA', | ||||||
|  |         'he', | ||||||
|         'hr', |         'hr', | ||||||
|         'it', |         'it', | ||||||
|         'ja', |         'ja', | ||||||
| @ -65,7 +70,9 @@ class TranslationsExport extends Command | |||||||
|         'ro', |         'ro', | ||||||
|         'ru_RU', |         'ru_RU', | ||||||
|         'sl', |         'sl', | ||||||
|  |         'sk', | ||||||
|         'sq', |         'sq', | ||||||
|  |         'sr', | ||||||
|         'sv', |         'sv', | ||||||
|         'th', |         'th', | ||||||
|         'tr_TR', |         'tr_TR', | ||||||
| @ -88,6 +95,49 @@ class TranslationsExport extends Command | |||||||
|      * @return mixed |      * @return mixed | ||||||
|      */ |      */ | ||||||
|     public function handle() |     public function handle() | ||||||
|  |     { | ||||||
|  |         $type =$this->option('type') ?? 'export'; | ||||||
|  | 
 | ||||||
|  |         if($type == 'import') | ||||||
|  |             $this->import(); | ||||||
|  | 
 | ||||||
|  |         if($type == 'export') | ||||||
|  |             $this->export(); | ||||||
|  | 
 | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private function import() | ||||||
|  |     { | ||||||
|  |         //loop and
 | ||||||
|  | 
 | ||||||
|  |         foreach($this->langs as $lang) | ||||||
|  |         { | ||||||
|  | 
 | ||||||
|  |             $import_file = "textsphp_{$lang}.php"; | ||||||
|  |             $dir = $this->option('path') ?? storage_path('lang_import/'); | ||||||
|  |             $path = $dir.$import_file; | ||||||
|  | 
 | ||||||
|  |             if(file_exists($path)){ | ||||||
|  |                 $this->logMessage($path); | ||||||
|  | 
 | ||||||
|  |                 $trans = file_get_contents($path); | ||||||
|  | 
 | ||||||
|  |                 file_put_contents(lang_path("/{$lang}/texts.php"), $trans); | ||||||
|  | 
 | ||||||
|  |             } | ||||||
|  |             else{ | ||||||
|  | 
 | ||||||
|  |                 $this->logMessage("Could not open file"); | ||||||
|  |                 $this->logMessage($path); | ||||||
|  |              | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  |     private function export() | ||||||
|     { |     { | ||||||
|         Storage::disk('local')->makeDirectory('lang'); |         Storage::disk('local')->makeDirectory('lang'); | ||||||
| 
 | 
 | ||||||
| @ -99,4 +149,12 @@ class TranslationsExport extends Command | |||||||
|             Storage::disk('local')->put("lang/{$lang}/{$lang}.json", json_encode(Arr::dot($translations), JSON_UNESCAPED_UNICODE)); |             Storage::disk('local')->put("lang/{$lang}/{$lang}.json", json_encode(Arr::dot($translations), JSON_UNESCAPED_UNICODE)); | ||||||
|         }  |         }  | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|  |     private function logMessage($str) | ||||||
|  |     { | ||||||
|  |         $str = date('Y-m-d h:i:s').' '.$str; | ||||||
|  |         $this->info($str); | ||||||
|  |         $this->log .= $str."\n"; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
| } | } | ||||||
|  | |||||||
| @ -22,7 +22,9 @@ use App\Jobs\Ninja\CompanySizeCheck; | |||||||
| use App\Jobs\Ninja\QueueSize; | use App\Jobs\Ninja\QueueSize; | ||||||
| use App\Jobs\Ninja\SystemMaintenance; | use App\Jobs\Ninja\SystemMaintenance; | ||||||
| use App\Jobs\Ninja\TaskScheduler; | use App\Jobs\Ninja\TaskScheduler; | ||||||
|  | use App\Jobs\Invoice\InvoiceCheckLateWebhook; | ||||||
| use App\Jobs\Quote\QuoteCheckExpired; | use App\Jobs\Quote\QuoteCheckExpired; | ||||||
|  | use App\Jobs\Subscription\CleanStaleInvoiceOrder; | ||||||
| use App\Jobs\Util\DiskCleanup; | use App\Jobs\Util\DiskCleanup; | ||||||
| use App\Jobs\Util\ReminderJob; | use App\Jobs\Util\ReminderJob; | ||||||
| use App\Jobs\Util\SchedulerCheck; | use App\Jobs\Util\SchedulerCheck; | ||||||
| @ -68,12 +70,18 @@ class Kernel extends ConsoleKernel | |||||||
|         /* Sends recurring invoices*/ |         /* Sends recurring invoices*/ | ||||||
|         $schedule->job(new RecurringInvoicesCron)->hourly()->withoutOverlapping()->name('recurring-invoice-job')->onOneServer(); |         $schedule->job(new RecurringInvoicesCron)->hourly()->withoutOverlapping()->name('recurring-invoice-job')->onOneServer(); | ||||||
| 
 | 
 | ||||||
|  |         /* Stale Invoice Cleanup*/ | ||||||
|  |         $schedule->job(new CleanStaleInvoiceOrder)->hourlyAt(30)->withoutOverlapping()->name('stale-invoice-job')->onOneServer(); | ||||||
|  | 
 | ||||||
|         /* Sends recurring invoices*/ |         /* Sends recurring invoices*/ | ||||||
|         $schedule->job(new RecurringExpensesCron)->dailyAt('00:10')->withoutOverlapping()->name('recurring-expense-job')->onOneServer(); |         $schedule->job(new RecurringExpensesCron)->dailyAt('00:10')->withoutOverlapping()->name('recurring-expense-job')->onOneServer(); | ||||||
| 
 | 
 | ||||||
|         /* Fires notifications for expired Quotes */ |         /* Fires notifications for expired Quotes */ | ||||||
|         $schedule->job(new QuoteCheckExpired)->dailyAt('05:10')->withoutOverlapping()->name('quote-expired-job')->onOneServer(); |         $schedule->job(new QuoteCheckExpired)->dailyAt('05:10')->withoutOverlapping()->name('quote-expired-job')->onOneServer(); | ||||||
| 
 | 
 | ||||||
|  |         /* Fires webhooks for overdue Invoice */ | ||||||
|  |         $schedule->job(new InvoiceCheckLateWebhook)->dailyAt('07:00')->withoutOverlapping()->name('invoice-overdue-job')->onOneServer(); | ||||||
|  | 
 | ||||||
|         /* Performs auto billing */ |         /* Performs auto billing */ | ||||||
|         $schedule->job(new AutoBillCron)->dailyAt('06:20')->withoutOverlapping()->name('auto-bill-job')->onOneServer(); |         $schedule->job(new AutoBillCron)->dailyAt('06:20')->withoutOverlapping()->name('auto-bill-job')->onOneServer(); | ||||||
| 
 | 
 | ||||||
| @ -81,7 +89,7 @@ class Kernel extends ConsoleKernel | |||||||
|         $schedule->job(new SchedulerCheck)->dailyAt('01:10')->withoutOverlapping(); |         $schedule->job(new SchedulerCheck)->dailyAt('01:10')->withoutOverlapping(); | ||||||
| 
 | 
 | ||||||
|         /* Checks for scheduled tasks */ |         /* Checks for scheduled tasks */ | ||||||
|         $schedule->job(new TaskScheduler())->dailyAt('06:50')->withoutOverlapping()->name('task-scheduler-job')->onOneServer(); |         $schedule->job(new TaskScheduler())->hourlyAt(10)->withoutOverlapping()->name('task-scheduler-job')->onOneServer(); | ||||||
| 
 | 
 | ||||||
|         /* Performs system maintenance such as pruning the backup table */ |         /* Performs system maintenance such as pruning the backup table */ | ||||||
|         $schedule->job(new SystemMaintenance)->sundays()->at('02:30')->withoutOverlapping()->name('system-maintenance-job')->onOneServer(); |         $schedule->job(new SystemMaintenance)->sundays()->at('02:30')->withoutOverlapping()->name('system-maintenance-job')->onOneServer(); | ||||||
|  | |||||||
| @ -93,6 +93,10 @@ class ClientRegistrationFields | |||||||
|                 'key' => 'vat_number', |                 'key' => 'vat_number', | ||||||
|                 'required' => false, |                 'required' => false, | ||||||
|             ], |             ], | ||||||
|  |             [ | ||||||
|  |                 'key' => 'currency_id', | ||||||
|  |                 'required' => false, | ||||||
|  |             ], | ||||||
|         ]; |         ]; | ||||||
| 
 | 
 | ||||||
|         return $data; |         return $data; | ||||||
|  | |||||||
| @ -441,7 +441,22 @@ class CompanySettings extends BaseSettings | |||||||
| 
 | 
 | ||||||
|     public $send_email_on_mark_paid = false; |     public $send_email_on_mark_paid = false; | ||||||
| 
 | 
 | ||||||
|  |     public $postmark_secret = ''; | ||||||
|  |      | ||||||
|  |     public $mailgun_secret = ''; | ||||||
|  |      | ||||||
|  |     public $mailgun_domain = ''; | ||||||
|  | 
 | ||||||
|  |     public $auto_bill_standard_invoices = false; | ||||||
|  | 
 | ||||||
|  |     public $email_alignment = 'center'; // center , left, right
 | ||||||
|  | 
 | ||||||
|     public static $casts = [ |     public static $casts = [ | ||||||
|  |         'email_alignment'                    => 'string', | ||||||
|  |         'auto_bill_standard_invoices'        => 'bool', | ||||||
|  |         'postmark_secret'                    => 'string', | ||||||
|  |         'mailgun_secret'                     => 'string', | ||||||
|  |         'mailgun_domain'                     => 'string', | ||||||
|         'send_email_on_mark_paid'            => 'bool', |         'send_email_on_mark_paid'            => 'bool', | ||||||
|         'vendor_portal_enable_uploads'       => 'bool', |         'vendor_portal_enable_uploads'       => 'bool', | ||||||
|         'besr_id'                            => 'string', |         'besr_id'                            => 'string', | ||||||
|  | |||||||
| @ -235,12 +235,17 @@ class EmailTemplateDefaults | |||||||
| 
 | 
 | ||||||
|     public static function emailStatementSubject() |     public static function emailStatementSubject() | ||||||
|     { |     { | ||||||
|         return ''; |         return ctrans('texts.your_statement'); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     public static function emailStatementTemplate() |     public static function emailStatementTemplate() | ||||||
|     { |     { | ||||||
|         return ''; | 
 | ||||||
|  |         $statement_message = '<p>$client<br><br>'.self::transformText('client_statement_body').'<br></p>'; | ||||||
|  | 
 | ||||||
|  |         return $statement_message; | ||||||
|  | 
 | ||||||
|  |         // return ctrans('texts.client_statement_body', ['start_date' => '$start_date', 'end_date' => '$end_date']);
 | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     private static function transformText($string) |     private static function transformText($string) | ||||||
|  | |||||||
							
								
								
									
										96
									
								
								app/DataMapper/Schedule/ClientStatement.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										96
									
								
								app/DataMapper/Schedule/ClientStatement.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,96 @@ | |||||||
|  | <?php | ||||||
|  | /** | ||||||
|  |  * Invoice Ninja (https://invoiceninja.com). | ||||||
|  |  * | ||||||
|  |  * @link https://github.com/invoiceninja/invoiceninja source repository | ||||||
|  |  * | ||||||
|  |  * @copyright Copyright (c) 2022. Invoice Ninja LLC (https://invoiceninja.com) | ||||||
|  |  * | ||||||
|  |  * @license https://www.elastic.co/licensing/elastic-license | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | namespace App\DataMapper; | ||||||
|  | 
 | ||||||
|  | use App\Models\Client; | ||||||
|  | use stdClass; | ||||||
|  | 
 | ||||||
|  | class ClientStatement | ||||||
|  | { | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * Defines the template name | ||||||
|  |      *  | ||||||
|  |      * @var string | ||||||
|  |      */ | ||||||
|  |     public string $template = 'client_statement'; | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * An array of clients hashed_ids | ||||||
|  |      * | ||||||
|  |      * Leave blank if this action should apply to all clients | ||||||
|  |      *  | ||||||
|  |      * @var array | ||||||
|  |      */ | ||||||
|  |     public array $clients = []; | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * The consts to be used to define the date_range variable of the statement | ||||||
|  |      */ | ||||||
|  |     public const THIS_MONTH = 'this_month'; | ||||||
|  |     public const THIS_QUARTER = 'this_quarter'; | ||||||
|  |     public const THIS_YEAR = 'this_year'; | ||||||
|  |     public const PREVIOUS_MONTH = 'previous_month'; | ||||||
|  |     public const PREVIOUS_QUARTER = 'previous_quarter'; | ||||||
|  |     public const PREVIOUS_YEAR = 'previous_year'; | ||||||
|  |     public const CUSTOM_RANGE = "custom_range"; | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * The date range the statement should include | ||||||
|  |      *  | ||||||
|  |      * @var string | ||||||
|  |      */ | ||||||
|  |     public string $date_range = 'this_month'; | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * If a custom range is select for the date range then | ||||||
|  |      * the start_date should be supplied in Y-m-d format | ||||||
|  |      *  | ||||||
|  |      * @var string | ||||||
|  |      */ | ||||||
|  |     public string $start_date = ''; | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * If a custom range is select for the date range then | ||||||
|  |      * the end_date should be supplied in Y-m-d format | ||||||
|  |      *  | ||||||
|  |      * @var string | ||||||
|  |      */ | ||||||
|  |     public string $end_date = ''; | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * Flag which allows the payment table | ||||||
|  |      * to be shown | ||||||
|  |      * | ||||||
|  |      * @var boolean | ||||||
|  |      */ | ||||||
|  |     public bool $show_payments_table = true; | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * Flag which allows the aging table | ||||||
|  |      * to be shown | ||||||
|  |      * | ||||||
|  |      * @var boolean | ||||||
|  |      */ | ||||||
|  |     public bool $show_aging_table = true; | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * String const which defines whether | ||||||
|  |      * the invoices to be shown are either | ||||||
|  |      * paid or unpaid | ||||||
|  |      *  | ||||||
|  |      * @var string | ||||||
|  |      */ | ||||||
|  |     public string $status = 'paid'; // paid | unpaid
 | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | } | ||||||
							
								
								
									
										138
									
								
								app/Export/CSV/ProductSalesExport.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										138
									
								
								app/Export/CSV/ProductSalesExport.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,138 @@ | |||||||
|  | <?php | ||||||
|  | /** | ||||||
|  |  * Invoice Ninja (https://invoiceninja.com). | ||||||
|  |  * | ||||||
|  |  * @link https://github.com/invoiceninja/invoiceninja source repository | ||||||
|  |  * | ||||||
|  |  * @copyright Copyright (c) 2022. Invoice Ninja LLC (https://invoiceninja.com) | ||||||
|  |  * | ||||||
|  |  * @license https://www.elastic.co/licensing/elastic-license | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | namespace App\Export\CSV; | ||||||
|  | 
 | ||||||
|  | use App\Libraries\MultiDB; | ||||||
|  | use App\Models\Client; | ||||||
|  | use App\Models\Company; | ||||||
|  | use App\Models\Credit; | ||||||
|  | use App\Models\Document; | ||||||
|  | use App\Models\Invoice; | ||||||
|  | use App\Models\Product; | ||||||
|  | use App\Transformers\ProductTransformer; | ||||||
|  | use App\Utils\Ninja; | ||||||
|  | use Illuminate\Support\Facades\App; | ||||||
|  | use League\Csv\Writer; | ||||||
|  | use Illuminate\Support\Carbon; | ||||||
|  | 
 | ||||||
|  | class ProductSalesExport extends BaseExport | ||||||
|  | { | ||||||
|  |     private Company $company; | ||||||
|  | 
 | ||||||
|  |     protected array $input; | ||||||
|  | 
 | ||||||
|  |     protected $date_key = 'created_at'; | ||||||
|  | 
 | ||||||
|  |     protected array $entity_keys = [ | ||||||
|  |         'custom_value1' => 'custom_value1', | ||||||
|  |         'custom_value2' => 'custom_value2', | ||||||
|  |         'custom_value3' => 'custom_value3', | ||||||
|  |         'custom_value4' => 'custom_value4', | ||||||
|  |         'product_key' => 'product_key', | ||||||
|  |         'notes' => 'notes', | ||||||
|  |         'cost' => 'cost', | ||||||
|  |         'price' => 'price', | ||||||
|  |         'quantity' => 'quantity', | ||||||
|  |         'tax_rate1' => 'tax_rate1', | ||||||
|  |         'tax_rate2' => 'tax_rate2', | ||||||
|  |         'tax_rate3' => 'tax_rate3', | ||||||
|  |         'tax_name1' => 'tax_name1', | ||||||
|  |         'tax_name2' => 'tax_name2', | ||||||
|  |         'tax_name3' => 'tax_name3', | ||||||
|  |         'is_amount_discount' => 'is_amount_discount', | ||||||
|  |         'discount' => 'discount', | ||||||
|  |         'line_total' => 'line_total', | ||||||
|  |         'gross_line_total' => 'gross_line_total', | ||||||
|  |         'status' => 'status', | ||||||
|  |         'date' => 'date', | ||||||
|  |         'currency' => 'currency', | ||||||
|  |         'client' => 'client', | ||||||
|  |     ]; | ||||||
|  | 
 | ||||||
|  |     private array $decorate_keys = [ | ||||||
|  |         'client', | ||||||
|  |         'currency', | ||||||
|  |         'date', | ||||||
|  |     ]; | ||||||
|  | 
 | ||||||
|  |     public function __construct(Company $company, array $input) | ||||||
|  |     { | ||||||
|  |         $this->company = $company; | ||||||
|  |         $this->input = $input; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     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 = Invoice::query() | ||||||
|  |                         ->withTrashed() | ||||||
|  |                         ->where('company_id', $this->company->id) | ||||||
|  |                         ->where('is_deleted', 0) | ||||||
|  |                         ->whereIn('status_id', [Invoice::STATUS_SENT, Invoice::STATUS_PARTIAL, Invoice::STATUS_PAID]); | ||||||
|  | 
 | ||||||
|  |         $query = $this->addDateRange($query); | ||||||
|  | 
 | ||||||
|  |         $query->cursor() | ||||||
|  |               ->each(function ($invoice) { | ||||||
|  | 
 | ||||||
|  |                   foreach($invoice->line_items as $item) | ||||||
|  |                     $this->csv->insertOne($this->buildRow($invoice, $item)); | ||||||
|  | 
 | ||||||
|  |               }); | ||||||
|  | 
 | ||||||
|  |         return $this->csv->toString(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private function buildRow($invoice, $invoice_item) :array | ||||||
|  |     { | ||||||
|  |         $transformed_entity = (array)$invoice_item; | ||||||
|  | 
 | ||||||
|  |         $entity = []; | ||||||
|  | 
 | ||||||
|  |         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] = ''; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         return $this->decorateAdvancedFields($invoice, $entity); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private function decorateAdvancedFields(Invoice $invoice, $entity) :array | ||||||
|  |     { | ||||||
|  |         $entity['client'] = $invoice->client->present()->name(); | ||||||
|  |         $entity['currency'] = $invoice->client->currency()->code; | ||||||
|  |         $entity['status'] = $invoice->stringStatus($invoice->status_id); | ||||||
|  |         $entity['date'] = Carbon::parse($invoice->date)->format($this->company->date_format()); | ||||||
|  | 
 | ||||||
|  |         return $entity; | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										32
									
								
								app/Factory/SchedulerFactory.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								app/Factory/SchedulerFactory.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,32 @@ | |||||||
|  | <?php | ||||||
|  | /** | ||||||
|  |  * Invoice Ninja (https://invoiceninja.com). | ||||||
|  |  * | ||||||
|  |  * @link https://github.com/invoiceninja/invoiceninja source repository | ||||||
|  |  * | ||||||
|  |  * @copyright Copyright (c) 2022. Invoice Ninja LLC (https://invoiceninja.com) | ||||||
|  |  * | ||||||
|  |  * @license https://www.elastic.co/licensing/elastic-license | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | namespace App\Factory; | ||||||
|  | 
 | ||||||
|  | use App\Models\Scheduler; | ||||||
|  | 
 | ||||||
|  | class SchedulerFactory | ||||||
|  | { | ||||||
|  |     public static function create($company_id, $user_id) :Scheduler | ||||||
|  |     { | ||||||
|  |         $scheduler = new Scheduler; | ||||||
|  | 
 | ||||||
|  |         $scheduler->name = ''; | ||||||
|  |         $scheduler->company_id = $company_id; | ||||||
|  |         $scheduler->user_id = $user_id; | ||||||
|  |         $scheduler->parameters = []; | ||||||
|  |         $scheduler->is_paused = false; | ||||||
|  |         $scheduler->is_deleted = false; | ||||||
|  |         $scheduler->template = ''; | ||||||
|  |          | ||||||
|  |         return $scheduler; | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -77,28 +77,45 @@ class BankTransactionFilters extends QueryFilters | |||||||
| 
 | 
 | ||||||
|         $status_parameters = explode(',', $value); |         $status_parameters = explode(',', $value); | ||||||
| 
 | 
 | ||||||
|  |         $status_array = []; | ||||||
|  |          | ||||||
|  |         $debit_or_withdrawal_array = []; | ||||||
|  | 
 | ||||||
|         if (in_array('all', $status_parameters)) { |         if (in_array('all', $status_parameters)) { | ||||||
|             return $this->builder; |             return $this->builder; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         if (in_array('unmatched', $status_parameters)) { |         if (in_array('unmatched', $status_parameters)) { | ||||||
|             $this->builder->where('status_id', BankTransaction::STATUS_UNMATCHED); |             $status_array[] = BankTransaction::STATUS_UNMATCHED; | ||||||
|  |             // $this->builder->orWhere('status_id', BankTransaction::STATUS_UNMATCHED);
 | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         if (in_array('matched', $status_parameters)) { |         if (in_array('matched', $status_parameters)) { | ||||||
|             $this->builder->where('status_id', BankTransaction::STATUS_MATCHED); |             $status_array[] = BankTransaction::STATUS_MATCHED; | ||||||
|  |             // $this->builder->where('status_id', BankTransaction::STATUS_MATCHED);
 | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         if (in_array('converted', $status_parameters)) { |         if (in_array('converted', $status_parameters)) { | ||||||
|             $this->builder->where('status_id', BankTransaction::STATUS_CONVERTED); |             $status_array[] = BankTransaction::STATUS_CONVERTED; | ||||||
|  |             // $this->builder->where('status_id', BankTransaction::STATUS_CONVERTED);
 | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         if (in_array('deposits', $status_parameters)) { |         if (in_array('deposits', $status_parameters)) { | ||||||
|             $this->builder->where('base_type', 'CREDIT'); |             $debit_or_withdrawal_array[] = 'CREDIT'; | ||||||
|  |             // $this->builder->where('base_type', 'CREDIT');
 | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         if (in_array('withdrawals', $status_parameters)) { |         if (in_array('withdrawals', $status_parameters)) { | ||||||
|             $this->builder->where('base_type', 'DEBIT'); |             $debit_or_withdrawal_array[] = 'DEBIT'; | ||||||
|  |             // $this->builder->where('base_type', 'DEBIT');
 | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         if(count($status_array) >=1) { | ||||||
|  |             $this->builder->whereIn('status_id', $status_array); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         if(count($debit_or_withdrawal_array) >=1) { | ||||||
|  |             $this->builder->orWhereIn('base_type', $debit_or_withdrawal_array); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         return $this->builder; |         return $this->builder; | ||||||
|  | |||||||
| @ -193,9 +193,7 @@ class ClientFilters extends QueryFilters | |||||||
|             ->where('clients.company_id', '=', $company_id) |             ->where('clients.company_id', '=', $company_id) | ||||||
|             ->where('client_contacts.is_primary', '=', true) |             ->where('client_contacts.is_primary', '=', true) | ||||||
|             ->where('client_contacts.deleted_at', '=', null) |             ->where('client_contacts.deleted_at', '=', null) | ||||||
|             //->whereRaw('(clients.name != "" or contacts.first_name != "" or contacts.last_name != "" or contacts.email != "")') // filter out buy now invoices
 |  | ||||||
|             ->select( |             ->select( | ||||||
|                // DB::raw('COALESCE(clients.currency_id, companies.currency_id) currency_id'),
 |  | ||||||
|                 DB::raw('COALESCE(clients.country_id, companies.country_id) country_id'), |                 DB::raw('COALESCE(clients.country_id, companies.country_id) country_id'), | ||||||
|                 DB::raw("CONCAT(COALESCE(client_contacts.first_name, ''), ' ', COALESCE(client_contacts.last_name, '')) contact"), |                 DB::raw("CONCAT(COALESCE(client_contacts.first_name, ''), ' ', COALESCE(client_contacts.last_name, '')) contact"), | ||||||
|                 'clients.id', |                 'clients.id', | ||||||
| @ -238,7 +236,6 @@ class ClientFilters extends QueryFilters | |||||||
|      */ |      */ | ||||||
|     public function entityFilter() |     public function entityFilter() | ||||||
|     { |     { | ||||||
|         //return $this->builder->whereCompanyId(auth()->user()->company()->id);
 |  | ||||||
|         return $this->builder->company(); |         return $this->builder->company(); | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | |||||||
| @ -105,7 +105,6 @@ class DesignFilters extends QueryFilters | |||||||
|         $query = DB::table('designs') |         $query = DB::table('designs') | ||||||
|             ->join('companies', 'companies.id', '=', 'designs.company_id') |             ->join('companies', 'companies.id', '=', 'designs.company_id') | ||||||
|             ->where('designs.company_id', '=', $company_id) |             ->where('designs.company_id', '=', $company_id) | ||||||
|             //->whereRaw('(designs.name != "" or contacts.first_name != "" or contacts.last_name != "" or contacts.email != "")') // filter out buy now invoices
 |  | ||||||
|             ->select( |             ->select( | ||||||
|                 'designs.id', |                 'designs.id', | ||||||
|                 'designs.name', |                 'designs.name', | ||||||
|  | |||||||
							
								
								
									
										124
									
								
								app/Filters/ExpenseCategoryFilters.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										124
									
								
								app/Filters/ExpenseCategoryFilters.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,124 @@ | |||||||
|  | <?php | ||||||
|  | /** | ||||||
|  |  * Invoice Ninja (https://invoiceninja.com). | ||||||
|  |  * | ||||||
|  |  * @link https://github.com/invoiceninja/invoiceninja source repository | ||||||
|  |  * | ||||||
|  |  * @copyright Copyright (c) 2022. Invoice Ninja LLC (https://invoiceninja.com) | ||||||
|  |  * | ||||||
|  |  * @license https://www.elastic.co/licensing/elastic-license | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | namespace App\Filters; | ||||||
|  | 
 | ||||||
|  | use App\Models\Expense; | ||||||
|  | use App\Models\User; | ||||||
|  | use Illuminate\Database\Eloquent\Builder; | ||||||
|  | use Illuminate\Support\Facades\DB; | ||||||
|  | use Illuminate\Support\Facades\Gate; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * ExpenseCategoryFilters. | ||||||
|  |  */ | ||||||
|  | class ExpenseCategoryFilters extends QueryFilters | ||||||
|  | { | ||||||
|  |     /** | ||||||
|  |      * Filter based on search text. | ||||||
|  |      * | ||||||
|  |      * @param string query filter | ||||||
|  |      * @return Builder | ||||||
|  |      * @deprecated | ||||||
|  |      */ | ||||||
|  |     public function filter(string $filter = '') : Builder | ||||||
|  |     { | ||||||
|  |         if (strlen($filter) == 0) { | ||||||
|  |             return $this->builder; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         return  $this->builder->where('expense_categories.name', 'like', '%'.$filter.'%'); | ||||||
|  | 
 | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * Filters the list based on the status | ||||||
|  |      * archived, active, deleted. | ||||||
|  |      * | ||||||
|  |      * @param string filter | ||||||
|  |      * @return Builder | ||||||
|  |      */ | ||||||
|  |     public function status(string $filter = '') : Builder | ||||||
|  |     { | ||||||
|  |         if (strlen($filter) == 0) { | ||||||
|  |             return $this->builder; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         $table = 'expense_categories'; | ||||||
|  |         $filters = explode(',', $filter); | ||||||
|  | 
 | ||||||
|  |         return $this->builder->where(function ($query) use ($filters, $table) { | ||||||
|  |             $query->whereNull($table.'.id'); | ||||||
|  | 
 | ||||||
|  |             if (in_array(parent::STATUS_ACTIVE, $filters)) { | ||||||
|  |                 $query->orWhereNull($table.'.deleted_at'); | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             if (in_array(parent::STATUS_ARCHIVED, $filters)) { | ||||||
|  |                 $query->orWhere(function ($query) use ($table) { | ||||||
|  |                     $query->whereNotNull($table.'.deleted_at'); | ||||||
|  | 
 | ||||||
|  |                     if (! in_array($table, ['users'])) { | ||||||
|  |                         $query->where($table.'.is_deleted', '=', 0); | ||||||
|  |                     } | ||||||
|  |                 }); | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             if (in_array(parent::STATUS_DELETED, $filters)) { | ||||||
|  |                 $query->orWhere($table.'.is_deleted', '=', 1); | ||||||
|  |             } | ||||||
|  |         }); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * Sorts the list based on $sort. | ||||||
|  |      * | ||||||
|  |      * @param string sort formatted as column|asc | ||||||
|  |      * @return Builder | ||||||
|  |      */ | ||||||
|  |     public function sort(string $sort) : Builder | ||||||
|  |     { | ||||||
|  |         $sort_col = explode('|', $sort); | ||||||
|  | 
 | ||||||
|  |         if (is_array($sort_col) && in_array($sort_col[1], ['asc', 'desc']) && in_array($sort_col[0], ['name'])) { | ||||||
|  |             return $this->builder->orderBy($sort_col[0], $sort_col[1]); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         return $this->builder; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * Returns the base query. | ||||||
|  |      * | ||||||
|  |      * @param int company_id | ||||||
|  |      * @param User $user | ||||||
|  |      * @return Builder | ||||||
|  |      * @deprecated | ||||||
|  |      */ | ||||||
|  |     public function baseQuery(int $company_id, User $user) : Builder | ||||||
|  |     { | ||||||
|  | 
 | ||||||
|  |         return $this->builder; | ||||||
|  | 
 | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * Filters the query by the users company ID. | ||||||
|  |      * | ||||||
|  |      * @return Illuminate\Database\Query\Builder | ||||||
|  |      */ | ||||||
|  |     public function entityFilter() | ||||||
|  |     { | ||||||
|  | 
 | ||||||
|  |         //return $this->builder->whereCompanyId(auth()->user()->company()->id);
 | ||||||
|  |         return $this->builder->company(); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -69,25 +69,54 @@ class ExpenseFilters extends QueryFilters | |||||||
|             return $this->builder; |             return $this->builder; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         if (in_array('logged', $status_parameters)) { |         $this->builder->whereNested(function ($query) use($status_parameters){ | ||||||
|             $this->builder->where('amount', '>', 0); |  | ||||||
|         } |  | ||||||
| 
 | 
 | ||||||
|         if (in_array('pending', $status_parameters)) { |             if (in_array('logged', $status_parameters)) { | ||||||
|             $this->builder->whereNull('invoice_id')->whereNotNull('payment_date'); |  | ||||||
|         } |  | ||||||
| 
 | 
 | ||||||
|         if (in_array('invoiced', $status_parameters)) { |                 $query->orWhere(function ($query){ | ||||||
|             $this->builder->whereNotNull('invoice_id'); |                     $query->where('amount', '>', 0) | ||||||
|         } |                           ->whereNull('invoice_id') | ||||||
|  |                           ->whereNull('payment_date'); | ||||||
|  |                 }); | ||||||
|                  |                  | ||||||
|         if (in_array('paid', $status_parameters)) { |             } | ||||||
|             $this->builder->whereNotNull('payment_date'); |  | ||||||
|         } |  | ||||||
| 
 | 
 | ||||||
|         if (in_array('unpaid', $status_parameters)) { |             if (in_array('pending', $status_parameters)) { | ||||||
|             $this->builder->whereNull('payment_date'); | 
 | ||||||
|         } |                 $query->orWhere(function ($query){ | ||||||
|  |                     $query->where('should_be_invoiced',true) | ||||||
|  |                           ->whereNull('invoice_id'); | ||||||
|  |                 }); | ||||||
|  |                  | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             if (in_array('invoiced', $status_parameters)) { | ||||||
|  | 
 | ||||||
|  |                 $query->orWhere(function ($query){ | ||||||
|  |                     $query->whereNotNull('invoice_id'); | ||||||
|  |                 }); | ||||||
|  |                  | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             if (in_array('paid', $status_parameters)) { | ||||||
|  | 
 | ||||||
|  |                 $query->orWhere(function ($query){ | ||||||
|  |                     $query->whereNotNull('payment_date'); | ||||||
|  |                 }); | ||||||
|  |                  | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             if (in_array('unpaid', $status_parameters)) { | ||||||
|  | 
 | ||||||
|  |                 $query->orWhere(function ($query){ | ||||||
|  |                     $query->whereNull('payment_date'); | ||||||
|  |                 }); | ||||||
|  |                  | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |         }); | ||||||
|  | 
 | ||||||
|  |         // nlog($this->builder->toSql());
 | ||||||
| 
 | 
 | ||||||
|         return $this->builder; |         return $this->builder; | ||||||
|     } |     } | ||||||
| @ -176,9 +205,7 @@ class ExpenseFilters extends QueryFilters | |||||||
|         $query = DB::table('expenses') |         $query = DB::table('expenses') | ||||||
|             ->join('companies', 'companies.id', '=', 'expenses.company_id') |             ->join('companies', 'companies.id', '=', 'expenses.company_id') | ||||||
|             ->where('expenses.company_id', '=', $company_id) |             ->where('expenses.company_id', '=', $company_id) | ||||||
|             //->whereRaw('(expenses.name != "" or contacts.first_name != "" or contacts.last_name != "" or contacts.email != "")') // filter out buy now invoices
 |  | ||||||
|             ->select( |             ->select( | ||||||
|                // DB::raw('COALESCE(expenses.currency_id, companies.currency_id) currency_id'),
 |  | ||||||
|                 DB::raw('COALESCE(expenses.country_id, companies.country_id) country_id'), |                 DB::raw('COALESCE(expenses.country_id, companies.country_id) country_id'), | ||||||
|                 DB::raw("CONCAT(COALESCE(expense_contacts.first_name, ''), ' ', COALESCE(expense_contacts.last_name, '')) contact"), |                 DB::raw("CONCAT(COALESCE(expense_contacts.first_name, ''), ' ', COALESCE(expense_contacts.last_name, '')) contact"), | ||||||
|                 'expenses.id', |                 'expenses.id', | ||||||
| @ -212,8 +239,6 @@ class ExpenseFilters extends QueryFilters | |||||||
|      */ |      */ | ||||||
|     public function entityFilter() |     public function entityFilter() | ||||||
|     { |     { | ||||||
| 
 |  | ||||||
|         //return $this->builder->whereCompanyId(auth()->user()->company()->id);
 |  | ||||||
|         return $this->builder->company(); |         return $this->builder->company(); | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | |||||||
| @ -16,6 +16,8 @@ use App\Models\User; | |||||||
| use App\Utils\Traits\MakesHash; | use App\Utils\Traits\MakesHash; | ||||||
| use Illuminate\Database\Eloquent\Builder; | use Illuminate\Database\Eloquent\Builder; | ||||||
| use Illuminate\Support\Carbon; | use Illuminate\Support\Carbon; | ||||||
|  | use InvalidArgumentException; | ||||||
|  | use RuntimeException; | ||||||
| 
 | 
 | ||||||
| /** | /** | ||||||
|  * InvoiceFilters. |  * InvoiceFilters. | ||||||
| @ -45,20 +47,27 @@ class InvoiceFilters extends QueryFilters | |||||||
| 
 | 
 | ||||||
|         $status_parameters = explode(',', $value); |         $status_parameters = explode(',', $value); | ||||||
| 
 | 
 | ||||||
|  |         $invoice_filters = []; | ||||||
|  | 
 | ||||||
|         if (in_array('all', $status_parameters)) { |         if (in_array('all', $status_parameters)) { | ||||||
|             return $this->builder; |             return $this->builder; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         if (in_array('paid', $status_parameters)) { |         if (in_array('paid', $status_parameters)) { | ||||||
|             $this->builder->where('status_id', Invoice::STATUS_PAID); |             $invoice_filters[] = Invoice::STATUS_PAID; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         if (in_array('unpaid', $status_parameters)) { |         if (in_array('unpaid', $status_parameters)) { | ||||||
|             $this->builder->whereIn('status_id', [Invoice::STATUS_SENT, Invoice::STATUS_PARTIAL]); |             $invoice_filters[] = Invoice::STATUS_SENT; | ||||||
|  |             $invoice_filters[] = Invoice::STATUS_PARTIAL; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         if(count($invoice_filters) >0){ | ||||||
|  |             $this->builder->whereIn('status_id', $invoice_filters); | ||||||
|         } |         } | ||||||
|          |          | ||||||
|         if (in_array('overdue', $status_parameters)) { |         if (in_array('overdue', $status_parameters)) { | ||||||
|             $this->builder->whereIn('status_id', [Invoice::STATUS_SENT, Invoice::STATUS_PARTIAL]) |             $this->builder->orWhereIn('status_id', [Invoice::STATUS_SENT, Invoice::STATUS_PARTIAL]) | ||||||
|                             ->where('due_date', '<', Carbon::now()) |                             ->where('due_date', '<', Carbon::now()) | ||||||
|                             ->orWhere('partial_due_date', '<', Carbon::now()); |                             ->orWhere('partial_due_date', '<', Carbon::now()); | ||||||
|         } |         } | ||||||
| @ -136,6 +145,10 @@ class InvoiceFilters extends QueryFilters | |||||||
|         }); |         }); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     /** | ||||||
|  |      * @return Builder  | ||||||
|  |      * @throws RuntimeException  | ||||||
|  |      */ | ||||||
|     public function without_deleted_clients() |     public function without_deleted_clients() | ||||||
|     { |     { | ||||||
| 
 | 
 | ||||||
| @ -144,6 +157,10 @@ class InvoiceFilters extends QueryFilters | |||||||
|                        }); |                        }); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     /** | ||||||
|  |      * @return Builder  | ||||||
|  |      * @throws InvalidArgumentException  | ||||||
|  |      */ | ||||||
|     public function upcoming() |     public function upcoming() | ||||||
|     { |     { | ||||||
|         return $this->builder |         return $this->builder | ||||||
| @ -154,6 +171,10 @@ class InvoiceFilters extends QueryFilters | |||||||
|                     ->orderBy('due_date', 'ASC'); |                     ->orderBy('due_date', 'ASC'); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     /** | ||||||
|  |      * @return void  | ||||||
|  |      * @throws InvalidArgumentException  | ||||||
|  |      */ | ||||||
|     public function overdue() |     public function overdue() | ||||||
|     { |     { | ||||||
|         $this->builder->whereIn('status_id', [Invoice::STATUS_SENT, Invoice::STATUS_PARTIAL]) |         $this->builder->whereIn('status_id', [Invoice::STATUS_SENT, Invoice::STATUS_PARTIAL]) | ||||||
| @ -165,6 +186,11 @@ class InvoiceFilters extends QueryFilters | |||||||
|                 ->orderBy('due_date', 'ASC'); |                 ->orderBy('due_date', 'ASC'); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     /** | ||||||
|  |      * @param string $client_id  | ||||||
|  |      * @return Builder  | ||||||
|  |      * @throws InvalidArgumentException  | ||||||
|  |      */ | ||||||
|     public function payable(string $client_id = '') |     public function payable(string $client_id = '') | ||||||
|     { |     { | ||||||
|         if (strlen($client_id) == 0) { |         if (strlen($client_id) == 0) { | ||||||
| @ -222,8 +248,20 @@ class InvoiceFilters extends QueryFilters | |||||||
|         } else {             |         } else {             | ||||||
|             return $this->builder->company()->with(['invitations.company'], ['documents.company']); |             return $this->builder->company()->with(['invitations.company'], ['documents.company']); | ||||||
|         } |         } | ||||||
|  |     } | ||||||
| 
 | 
 | ||||||
| //            return $this->builder->whereCompanyId(auth()->user()->company()->id);
 |     /** | ||||||
|  |      * @param string $filter  | ||||||
|  |      * @return Builder  | ||||||
|  |      * @throws InvalidArgumentException  | ||||||
|  |      */ | ||||||
|  |     public function private_notes($filter = '') :Builder | ||||||
|  |     { | ||||||
|  |         if (strlen($filter) == 0) { | ||||||
|  |             return $this->builder; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         return $this->builder->where('private_notes', 'LIKE', '%'.$filter.'%'); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /** |     /** | ||||||
|  | |||||||
| @ -84,12 +84,17 @@ class PaymentFilters extends QueryFilters | |||||||
|     /** |     /** | ||||||
|      * Returns a list of payments that can be matched to bank transactions |      * Returns a list of payments that can be matched to bank transactions | ||||||
|      */ |      */ | ||||||
|     public function match_transactions($value = '') |     public function match_transactions($value = 'true') :Builder | ||||||
|     { |     { | ||||||
| 
 | 
 | ||||||
|         if($value == 'true') |         if($value == 'true'){ | ||||||
|         { |             return $this->builder | ||||||
|             return $this->builder->where('is_deleted',0)->whereNull('transaction_id'); |                         ->where('is_deleted',0) | ||||||
|  |                         ->where(function ($query){ | ||||||
|  |                             $query->whereNull('transaction_id') | ||||||
|  |                             ->orWhere("transaction_id",""); | ||||||
|  |                         }); | ||||||
|  |                          | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         return $this->builder; |         return $this->builder; | ||||||
|  | |||||||
| @ -42,20 +42,26 @@ class PurchaseOrderFilters extends QueryFilters | |||||||
|             return $this->builder; |             return $this->builder; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  |         $po_status = []; | ||||||
|  | 
 | ||||||
|         if (in_array('draft', $status_parameters)) { |         if (in_array('draft', $status_parameters)) { | ||||||
|             $this->builder->where('status_id', PurchaseOrder::STATUS_DRAFT); |             $po_status[] = PurchaseOrder::STATUS_DRAFT; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         if (in_array('sent', $status_parameters)) { |         if (in_array('sent', $status_parameters)) { | ||||||
|             $this->builder->where('status_id', PurchaseOrder::STATUS_SENT); |             $po_status[] = PurchaseOrder::STATUS_SENT; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         if (in_array('accepted', $status_parameters)) { |         if (in_array('accepted', $status_parameters)) { | ||||||
|             $this->builder->where('status_id', PurchaseOrder::STATUS_ACCEPTED); |             $po_status[] = PurchaseOrder::STATUS_ACCEPTED; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         if (in_array('cancelled', $status_parameters)) { |         if (in_array('cancelled', $status_parameters)) { | ||||||
|             $this->builder->where('status_id', PurchaseOrder::STATUS_CANCELLED); |             $po_status[] = PurchaseOrder::STATUS_CANCELLED; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         if(count($status_parameters) >=1) { | ||||||
|  |             $this->builder->whereIn('status_id', $status_parameters); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         return $this->builder; |         return $this->builder; | ||||||
|  | |||||||
| @ -15,6 +15,7 @@ namespace App\Filters; | |||||||
| use App\Utils\Traits\MakesHash; | use App\Utils\Traits\MakesHash; | ||||||
| use Illuminate\Database\Eloquent\Builder; | use Illuminate\Database\Eloquent\Builder; | ||||||
| use Illuminate\Http\Request; | use Illuminate\Http\Request; | ||||||
|  | use Illuminate\Support\Carbon; | ||||||
| 
 | 
 | ||||||
| /** | /** | ||||||
|  * Class QueryFilters. |  * Class QueryFilters. | ||||||
| @ -173,22 +174,30 @@ abstract class QueryFilters | |||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     public function created_at($value) |     public function created_at($value = '') | ||||||
|     { |     { | ||||||
|         $created_at = $value ? (int) $value : 0; |  | ||||||
|          |          | ||||||
|         $created_at = date('Y-m-d H:i:s', $value); |         if($value == '') | ||||||
|  |             return $this->builder; | ||||||
| 
 | 
 | ||||||
|         if(is_string($created_at)){ |         try{ | ||||||
| 
 | 
 | ||||||
|             $created_at = strtotime(str_replace("/","-",$created_at)); |             if(is_numeric($value)){ | ||||||
|  |                 $created_at = Carbon::createFromTimestamp((int)$value); | ||||||
|  |             } | ||||||
|  |             else{ | ||||||
|  |                 $created_at = Carbon::parse($value); | ||||||
|  |             } | ||||||
| 
 | 
 | ||||||
|             if(!$created_at) |             return $this->builder->where('created_at', '>=', $created_at); | ||||||
|                 return $this->builder; | 
 | ||||||
|  |         } | ||||||
|  |         catch(\Exception $e) { | ||||||
|  | 
 | ||||||
|  |             return $this->builder; | ||||||
| 
 | 
 | ||||||
|         } |         } | ||||||
|          |          | ||||||
|         return $this->builder->where('created_at', '>=', $created_at); |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     public function is_deleted($value) |     public function is_deleted($value) | ||||||
| @ -209,6 +218,15 @@ abstract class QueryFilters | |||||||
|         return $this->builder->where('client_id', $this->decodePrimaryKey($client_id)); |         return $this->builder->where('client_id', $this->decodePrimaryKey($client_id)); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     public function vendor_id(string $vendor_id = '') :Builder | ||||||
|  |     { | ||||||
|  |         if (strlen($vendor_id) == 0) { | ||||||
|  |             return $this->builder; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         return $this->builder->where('vendor_id', $this->decodePrimaryKey($vendor_id)); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     public function filter_deleted_clients($value) |     public function filter_deleted_clients($value) | ||||||
|     { |     { | ||||||
|         if ($value == 'true') { |         if ($value == 'true') { | ||||||
| @ -226,12 +244,6 @@ abstract class QueryFilters | |||||||
|             return $this->builder->where('is_deleted', 0); |             return $this->builder->where('is_deleted', 0); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         // if($value == 'true'){
 |  | ||||||
| 
 |  | ||||||
|         //     $this->builder->withTrashed();
 |  | ||||||
| 
 |  | ||||||
|         // }
 |  | ||||||
| 
 |  | ||||||
|         return $this->builder; |         return $this->builder; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| @ -239,6 +251,7 @@ abstract class QueryFilters | |||||||
|     { |     { | ||||||
|         return $this->builder |         return $this->builder | ||||||
|             ->orWhere($this->with_property, $value) |             ->orWhere($this->with_property, $value) | ||||||
|             ->orderByRaw("{$this->with_property} = ? DESC", [$value]); |             ->orderByRaw("{$this->with_property} = ? DESC", [$value]) | ||||||
|  |             ->company(); | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | |||||||
| @ -66,27 +66,40 @@ class QuoteFilters extends QueryFilters | |||||||
|             return $this->builder; |             return $this->builder; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  |         $quote_filters = []; | ||||||
|  | 
 | ||||||
|         if (in_array('draft', $status_parameters)) { |         if (in_array('draft', $status_parameters)) { | ||||||
|             $this->builder->where('status_id', Quote::STATUS_DRAFT); |             $quote_filters[] = Quote::STATUS_DRAFT; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         if (in_array('sent', $status_parameters)) { |         if (in_array('sent', $status_parameters)) { | ||||||
|             $this->builder->where('status_id', Quote::STATUS_SENT); |             $quote_filters[] = Quote::STATUS_SENT; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         if (in_array('approved', $status_parameters)) { |         if (in_array('approved', $status_parameters)) { | ||||||
|             $this->builder->where('status_id', Quote::STATUS_APPROVED); |             $quote_filters[] = Quote::STATUS_APPROVED; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         if(count($quote_filters) >=1){ | ||||||
|  |             $this->builder->whereIn('status_id', $quote_filters); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         if (in_array('expired', $status_parameters)) { |         if (in_array('expired', $status_parameters)) { | ||||||
|             $this->builder->where('status_id', Quote::STATUS_SENT) |             $this->builder->orWhere(function ($query){ | ||||||
|                           ->where('due_date', '>=', now()->toDateString()); |                           $query->where('status_id', Quote::STATUS_SENT) | ||||||
|  |                           ->company() | ||||||
|  |                           ->whereNotNull('due_date') | ||||||
|  |                           ->where('due_date', '<=', now()->toDateString()); | ||||||
|  |                       }); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         if (in_array('upcoming', $status_parameters)) { |         if (in_array('upcoming', $status_parameters)) { | ||||||
|             $this->builder->where('status_id', Quote::STATUS_SENT) |             $this->builder->orWhere(function ($query){ | ||||||
|                           ->where('due_date', '<=', now()->toDateString()) |                         $query->where('status_id', Quote::STATUS_SENT) | ||||||
|  |                           ->company() | ||||||
|  |                           ->where('due_date', '>=', now()->toDateString()) | ||||||
|                           ->orderBy('due_date', 'DESC'); |                           ->orderBy('due_date', 'DESC'); | ||||||
|  |                       }); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         return $this->builder; |         return $this->builder; | ||||||
|  | |||||||
							
								
								
									
										129
									
								
								app/Filters/SubscriptionFilters.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										129
									
								
								app/Filters/SubscriptionFilters.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,129 @@ | |||||||
|  | <?php | ||||||
|  | /** | ||||||
|  |  * Invoice Ninja (https://invoiceninja.com). | ||||||
|  |  * | ||||||
|  |  * @link https://github.com/invoiceninja/invoiceninja source repository | ||||||
|  |  * | ||||||
|  |  * @copyright Copyright (c) 2022. Invoice Ninja LLC (https://invoiceninja.com) | ||||||
|  |  * | ||||||
|  |  * @license https://www.elastic.co/licensing/elastic-license | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | namespace App\Filters; | ||||||
|  | 
 | ||||||
|  | use App\Models\User; | ||||||
|  | use App\Models\Webhook; | ||||||
|  | use Illuminate\Database\Eloquent\Builder; | ||||||
|  | use Illuminate\Support\Facades\DB; | ||||||
|  | use Illuminate\Support\Facades\Gate; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * SubscriptionFilters. | ||||||
|  |  */ | ||||||
|  | class SubscriptionFilters extends QueryFilters | ||||||
|  | { | ||||||
|  |     /** | ||||||
|  |      * Filter based on search text. | ||||||
|  |      * | ||||||
|  |      * @param string query filter | ||||||
|  |      * @return Builder | ||||||
|  |      * @deprecated | ||||||
|  |      */ | ||||||
|  |     public function filter(string $filter = '') : Builder | ||||||
|  |     { | ||||||
|  |         if (strlen($filter) == 0) { | ||||||
|  |             return $this->builder; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         return  $this->builder->where(function ($query) use ($filter) { | ||||||
|  |             $query->where('name', 'like', '%'.$filter.'%'); | ||||||
|  |         }); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * Filters the list based on the status | ||||||
|  |      * archived, active, deleted. | ||||||
|  |      * | ||||||
|  |      * @param string filter | ||||||
|  |      * @return Builder | ||||||
|  |      */ | ||||||
|  |     public function status(string $filter = '') : Builder | ||||||
|  |     { | ||||||
|  |         if (strlen($filter) == 0) { | ||||||
|  |             return $this->builder; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         $table = 'subscriptions'; | ||||||
|  |         $filters = explode(',', $filter); | ||||||
|  | 
 | ||||||
|  |         return $this->builder->where(function ($query) use ($filters, $table) { | ||||||
|  |             $query->whereNull($table.'.id'); | ||||||
|  | 
 | ||||||
|  |             if (in_array(parent::STATUS_ACTIVE, $filters)) { | ||||||
|  |                 $query->orWhereNull($table.'.deleted_at'); | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             if (in_array(parent::STATUS_ARCHIVED, $filters)) { | ||||||
|  |                 $query->orWhere(function ($query) use ($table) { | ||||||
|  |                     $query->whereNotNull($table.'.deleted_at'); | ||||||
|  | 
 | ||||||
|  |                     if (! in_array($table, ['users'])) { | ||||||
|  |                         $query->where($table.'.is_deleted', '=', 0); | ||||||
|  |                     } | ||||||
|  |                 }); | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             if (in_array(parent::STATUS_DELETED, $filters)) { | ||||||
|  |                 $query->orWhere($table.'.is_deleted', '=', 1); | ||||||
|  |             } | ||||||
|  |         }); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * Sorts the list based on $sort. | ||||||
|  |      * | ||||||
|  |      * @param string sort formatted as column|asc | ||||||
|  |      * @return Builder | ||||||
|  |      */ | ||||||
|  |     public function sort(string $sort) : Builder | ||||||
|  |     { | ||||||
|  |         $sort_col = explode('|', $sort); | ||||||
|  | 
 | ||||||
|  |         return $this->builder->orderBy($sort_col[0], $sort_col[1]); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * Returns the base query. | ||||||
|  |      * | ||||||
|  |      * @param int company_id | ||||||
|  |      * @param User $user | ||||||
|  |      * @return Builder | ||||||
|  |      * @deprecated | ||||||
|  |      */ | ||||||
|  |     public function baseQuery(int $company_id, User $user) : Builder | ||||||
|  |     { | ||||||
|  |         $query = DB::table('subscriptions') | ||||||
|  |             ->join('companies', 'companies.id', '=', 'subscriptions.company_id') | ||||||
|  |             ->where('subscriptions.company_id', '=', $company_id); | ||||||
|  | 
 | ||||||
|  |         /* | ||||||
|  |          * If the user does not have permissions to view all invoices | ||||||
|  |          * limit the user to only the invoices they have created | ||||||
|  |          */ | ||||||
|  |         if (Gate::denies('view-list', Webhook::class)) { | ||||||
|  |             $query->where('subscriptions.user_id', '=', $user->id); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         return $query; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * Filters the query by the users company ID. | ||||||
|  |      * | ||||||
|  |      * @return Illuminate\Database\Query\Builder | ||||||
|  |      */ | ||||||
|  |     public function entityFilter() | ||||||
|  |     { | ||||||
|  |         return $this->builder->company(); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -104,7 +104,6 @@ class TokenFilters extends QueryFilters | |||||||
|         $query = DB::table('company_tokens') |         $query = DB::table('company_tokens') | ||||||
|             ->join('companies', 'companies.id', '=', 'company_tokens.company_id') |             ->join('companies', 'companies.id', '=', 'company_tokens.company_id') | ||||||
|             ->where('company_tokens.company_id', '=', $company_id) |             ->where('company_tokens.company_id', '=', $company_id) | ||||||
|             //->whereRaw('(designs.name != "" or contacts.first_name != "" or contacts.last_name != "" or contacts.email != "")') // filter out buy now invoices
 |  | ||||||
|             ->select( |             ->select( | ||||||
|                 'company_tokens.id', |                 'company_tokens.id', | ||||||
|                 'company_tokens.name', |                 'company_tokens.name', | ||||||
|  | |||||||
| @ -118,7 +118,6 @@ class VendorFilters extends QueryFilters | |||||||
|             ->where('vendors.company_id', '=', $company_id) |             ->where('vendors.company_id', '=', $company_id) | ||||||
|             ->where('vendor_contacts.is_primary', '=', true) |             ->where('vendor_contacts.is_primary', '=', true) | ||||||
|             ->where('vendor_contacts.deleted_at', '=', null) |             ->where('vendor_contacts.deleted_at', '=', null) | ||||||
|             //->whereRaw('(vendors.name != "" or contacts.first_name != "" or contacts.last_name != "" or contacts.email != "")') // filter out buy now invoices
 |  | ||||||
|             ->select( |             ->select( | ||||||
|                // DB::raw('COALESCE(vendors.currency_id, companies.currency_id) currency_id'),
 |                // DB::raw('COALESCE(vendors.currency_id, companies.currency_id) currency_id'),
 | ||||||
|                 DB::raw('COALESCE(vendors.country_id, companies.country_id) country_id'), |                 DB::raw('COALESCE(vendors.country_id, companies.country_id) country_id'), | ||||||
|  | |||||||
| @ -105,7 +105,6 @@ class WebhookFilters extends QueryFilters | |||||||
|         $query = DB::table('webhooks') |         $query = DB::table('webhooks') | ||||||
|             ->join('companies', 'companies.id', '=', 'webhooks.company_id') |             ->join('companies', 'companies.id', '=', 'webhooks.company_id') | ||||||
|             ->where('webhooks.company_id', '=', $company_id) |             ->where('webhooks.company_id', '=', $company_id) | ||||||
|             //->whereRaw('(designs.name != "" or contacts.first_name != "" or contacts.last_name != "" or contacts.email != "")') // filter out buy now invoices
 |  | ||||||
|             ->select( |             ->select( | ||||||
|                 'webhooks.id', |                 'webhooks.id', | ||||||
|                 'webhooks.target_url', |                 'webhooks.target_url', | ||||||
|  | |||||||
| @ -13,6 +13,7 @@ namespace App\Helpers\Epc; | |||||||
| 
 | 
 | ||||||
| use App\Models\Company; | use App\Models\Company; | ||||||
| use App\Models\Invoice; | use App\Models\Invoice; | ||||||
|  | use App\Models\RecurringInvoice; | ||||||
| use App\Utils\Ninja; | use App\Utils\Ninja; | ||||||
| use BaconQrCode\Renderer\ImageRenderer; | use BaconQrCode\Renderer\ImageRenderer; | ||||||
| use BaconQrCode\Renderer\Image\SvgImageBackEnd; | use BaconQrCode\Renderer\Image\SvgImageBackEnd; | ||||||
| @ -35,7 +36,7 @@ class EpcQrGenerator | |||||||
| 
 | 
 | ||||||
|     ]; |     ]; | ||||||
| 
 | 
 | ||||||
|     public function __construct(protected Company $company, protected Invoice $invoice, protected float $amount){} |     public function __construct(protected Company $company, protected Invoice|RecurringInvoice $invoice, protected float $amount){} | ||||||
| 
 | 
 | ||||||
|     public function getQrCode() |     public function getQrCode() | ||||||
|     { |     { | ||||||
|  | |||||||
| @ -87,10 +87,10 @@ class SwissQrGenerator | |||||||
|     $qrBill->setUltimateDebtor( |     $qrBill->setUltimateDebtor( | ||||||
|         QrBill\DataGroup\Element\StructuredAddress::createWithStreet( |         QrBill\DataGroup\Element\StructuredAddress::createWithStreet( | ||||||
|             substr($this->client->present()->name(), 0 , 70), |             substr($this->client->present()->name(), 0 , 70), | ||||||
|             $this->client->address1 ? substr($this->client->address1, 0 , 70) : '_', |             $this->client->address1 ? substr($this->client->address1, 0 , 70) : ' ', | ||||||
|             $this->client->address2 ? substr($this->client->address2, 0 , 16) : '_', |             $this->client->address2 ? substr($this->client->address2, 0 , 16) : ' ', | ||||||
|             $this->client->postal_code ? substr($this->client->postal_code, 0, 16) : '_', |             $this->client->postal_code ? substr($this->client->postal_code, 0, 16) : ' ', | ||||||
|             $this->client->city ? substr($this->client->city, 0, 35) : '_', |             $this->client->city ? substr($this->client->city, 0, 35) : ' ', | ||||||
|             'CH' |             'CH' | ||||||
|         )); |         )); | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -112,6 +112,7 @@ class ActivityController extends BaseController | |||||||
|                     'purchase_order' => $activity->purchase_order ? $activity->purchase_order : '', |                     'purchase_order' => $activity->purchase_order ? $activity->purchase_order : '', | ||||||
|                     'subscription' => $activity->subscription ? $activity->subscription : '', |                     'subscription' => $activity->subscription ? $activity->subscription : '', | ||||||
|                     'vendor_contact' => $activity->vendor_contact ? $activity->vendor_contact : '', |                     'vendor_contact' => $activity->vendor_contact ? $activity->vendor_contact : '', | ||||||
|  |                     'recurring_expense' => $activity->recurring_expense ? $activity->recurring_expense : '', | ||||||
|                 ]; |                 ]; | ||||||
| 
 | 
 | ||||||
|                 return array_merge($arr, $activity->toArray()); |                 return array_merge($arr, $activity->toArray()); | ||||||
|  | |||||||
| @ -51,6 +51,7 @@ class ContactRegisterController extends Controller | |||||||
| 
 | 
 | ||||||
|     public function register(RegisterRequest $request) |     public function register(RegisterRequest $request) | ||||||
|     { |     { | ||||||
|  | 
 | ||||||
|         $request->merge(['company' => $request->company()]); |         $request->merge(['company' => $request->company()]); | ||||||
| 
 | 
 | ||||||
|         $client = $this->getClient($request->all()); |         $client = $this->getClient($request->all()); | ||||||
| @ -58,7 +59,7 @@ class ContactRegisterController extends Controller | |||||||
| 
 | 
 | ||||||
|         Auth::guard('contact')->loginUsingId($client_contact->id, true); |         Auth::guard('contact')->loginUsingId($client_contact->id, true); | ||||||
| 
 | 
 | ||||||
|         return redirect()->route('client.dashboard'); |         return redirect()->intended(route('client.dashboard')); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     private function getClient(array $data) |     private function getClient(array $data) | ||||||
| @ -66,7 +67,15 @@ class ContactRegisterController extends Controller | |||||||
|         $client = ClientFactory::create($data['company']->id, $data['company']->owner()->id); |         $client = ClientFactory::create($data['company']->id, $data['company']->owner()->id); | ||||||
| 
 | 
 | ||||||
|         $client->fill($data); |         $client->fill($data); | ||||||
|  | 
 | ||||||
|         $client->save(); |         $client->save(); | ||||||
|  | 
 | ||||||
|  |         if(isset($data['currency_id'])) { | ||||||
|  |             $settings = $client->settings; | ||||||
|  |             $settings->currency_id = isset($data['currency_id']) ? $data['currency_id'] : $data['company']->settings->currency_id; | ||||||
|  |             $client->settings = $settings; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|         $client->number = $this->getNextClientNumber($client); |         $client->number = $this->getNextClientNumber($client); | ||||||
|         $client->save(); |         $client->save(); | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -984,6 +984,9 @@ class BaseController extends Controller | |||||||
|             //pass report errors bool to front end
 |             //pass report errors bool to front end
 | ||||||
|             $data['report_errors'] = Ninja::isSelfHost() ? $account->report_errors : true; |             $data['report_errors'] = Ninja::isSelfHost() ? $account->report_errors : true; | ||||||
| 
 | 
 | ||||||
|  |             //pass whitelabel bool to front end
 | ||||||
|  |             $data['white_label'] = Ninja::isSelfHost() ? $account->isPaid() : false; | ||||||
|  | 
 | ||||||
|             //pass referral code to front end
 |             //pass referral code to front end
 | ||||||
|             $data['rc'] = request()->has('rc') ? request()->input('rc') : ''; |             $data['rc'] = request()->has('rc') ? request()->input('rc') : ''; | ||||||
|             $data['build'] = request()->has('build') ? request()->input('build') : ''; |             $data['build'] = request()->has('build') ? request()->input('build') : ''; | ||||||
|  | |||||||
| @ -52,7 +52,7 @@ class InvoiceController extends Controller | |||||||
|      * |      * | ||||||
|      * @return Factory|View |      * @return Factory|View | ||||||
|      */ |      */ | ||||||
|     public function show(ShowInvoiceRequest $request, Invoice $invoice) |     public function show(ShowInvoiceRequest $request, Invoice $invoice, ?string $hash = null) | ||||||
|     { |     { | ||||||
|         set_time_limit(0); |         set_time_limit(0); | ||||||
| 
 | 
 | ||||||
| @ -69,6 +69,7 @@ class InvoiceController extends Controller | |||||||
|             'invoice' => $invoice, |             'invoice' => $invoice, | ||||||
|             'invitation' => $invitation ?: $invoice->invitations->first(), |             'invitation' => $invitation ?: $invoice->invitations->first(), | ||||||
|             'key' => $invitation ? $invitation->key : false, |             'key' => $invitation ? $invitation->key : false, | ||||||
|  |             'hash' => $hash, | ||||||
|         ]; |         ]; | ||||||
| 
 | 
 | ||||||
|         if ($request->query('mode') === 'fullscreen') { |         if ($request->query('mode') === 'fullscreen') { | ||||||
|  | |||||||
| @ -26,6 +26,7 @@ use App\Models\Invoice; | |||||||
| use App\Models\RecurringInvoice; | use App\Models\RecurringInvoice; | ||||||
| use App\Models\Subscription; | use App\Models\Subscription; | ||||||
| use App\Notifications\Ninja\NewAccountNotification; | use App\Notifications\Ninja\NewAccountNotification; | ||||||
|  | use App\Repositories\RecurringInvoiceRepository; | ||||||
| use App\Repositories\SubscriptionRepository; | use App\Repositories\SubscriptionRepository; | ||||||
| use App\Utils\Ninja; | use App\Utils\Ninja; | ||||||
| use App\Utils\Traits\MakesHash; | use App\Utils\Traits\MakesHash; | ||||||
| @ -147,6 +148,7 @@ class NinjaPlanController extends Controller | |||||||
|             $account->plan_term = 'month'; |             $account->plan_term = 'month'; | ||||||
|             $account->plan_started = now(); |             $account->plan_started = now(); | ||||||
|             $account->plan_expires = now()->addDays(14); |             $account->plan_expires = now()->addDays(14); | ||||||
|  |             $account->is_trial=true; | ||||||
|             $account->save(); |             $account->save(); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
| @ -178,6 +180,15 @@ class NinjaPlanController extends Controller | |||||||
|                  ->increment() |                  ->increment() | ||||||
|                  ->queue(); |                  ->queue(); | ||||||
| 
 | 
 | ||||||
|  | 
 | ||||||
|  |         $old_recurring = RecurringInvoice::where('company_id', config('ninja.ninja_default_company_id'))->where('client_id', $client->id)->first(); | ||||||
|  | 
 | ||||||
|  |         if($old_recurring) { | ||||||
|  |             $old_recurring->service()->stop()->save(); | ||||||
|  |             $old_recurring_repo = new RecurringInvoiceRepository(); | ||||||
|  |             $old_recurring_repo->archive($old_recurring); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|         $ninja_company = Company::on('db-ninja-01')->find(config('ninja.ninja_default_company_id')); |         $ninja_company = Company::on('db-ninja-01')->find(config('ninja.ninja_default_company_id')); | ||||||
|         $ninja_company->notification(new NewAccountNotification($subscription->company->account, $client))->ninja(); |         $ninja_company->notification(new NewAccountNotification($subscription->company->account, $client))->ninja(); | ||||||
| 
 | 
 | ||||||
| @ -206,7 +217,7 @@ class NinjaPlanController extends Controller | |||||||
| 
 | 
 | ||||||
|             if ($account) { |             if ($account) { | ||||||
|                 //offer the option to have a free trial
 |                 //offer the option to have a free trial
 | ||||||
|                 if (! $account->trial_started && ! $account->plan) { |                 if (!$account->is_trial) { | ||||||
|                     return $this->trial(); |                     return $this->trial(); | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -148,8 +148,17 @@ class PaymentController extends Controller | |||||||
| 
 | 
 | ||||||
|         $payment = $payment->service()->applyCredits($payment_hash)->save(); |         $payment = $payment->service()->applyCredits($payment_hash)->save(); | ||||||
| 
 | 
 | ||||||
|  |         $invoices = Invoice::whereIn('id', $this->transformKeys(array_column($payment_hash->invoices(), 'invoice_id'))); | ||||||
|  | 
 | ||||||
|         event('eloquent.created: App\Models\Payment', $payment); |         event('eloquent.created: App\Models\Payment', $payment); | ||||||
| 
 | 
 | ||||||
|  |         if($invoices->sum('balance') > 0){ | ||||||
|  | 
 | ||||||
|  |             $invoice = $invoices->first(); | ||||||
|  | 
 | ||||||
|  |             return redirect()->route('client.invoice.show', ['invoice' => $invoice->hashed_id, 'hash' => $request->input('hash')]); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|         if (property_exists($payment_hash->data, 'billing_context')) { |         if (property_exists($payment_hash->data, 'billing_context')) { | ||||||
|             $billing_subscription = \App\Models\Subscription::find($payment_hash->data->billing_context->subscription_id); |             $billing_subscription = \App\Models\Subscription::find($payment_hash->data->billing_context->subscription_id); | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -13,6 +13,7 @@ | |||||||
| namespace App\Http\Controllers\ClientPortal; | namespace App\Http\Controllers\ClientPortal; | ||||||
| 
 | 
 | ||||||
| use App\Http\Controllers\Controller; | use App\Http\Controllers\Controller; | ||||||
|  | use App\Http\Requests\ClientPortal\RecurringInvoices\ShowRecurringInvoiceRequest; | ||||||
| use App\Models\RecurringInvoice; | use App\Models\RecurringInvoice; | ||||||
| use App\Utils\Ninja; | use App\Utils\Ninja; | ||||||
| use Illuminate\Http\Request; | use Illuminate\Http\Request; | ||||||
| @ -38,4 +39,20 @@ class SubscriptionController extends Controller | |||||||
| 
 | 
 | ||||||
|         return render('subscriptions.index'); |         return render('subscriptions.index'); | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * Display the recurring invoice. | ||||||
|  |      * | ||||||
|  |      * @param ShowRecurringInvoiceRequest $request | ||||||
|  |      * @param RecurringInvoice $recurring_invoice | ||||||
|  |      * @return Factory|View | ||||||
|  |      */ | ||||||
|  |     public function show(ShowRecurringInvoiceRequest $request, RecurringInvoice $recurring_invoice) | ||||||
|  |     { | ||||||
|  |         return $this->render('subscriptions.show', [ | ||||||
|  |             'invoice' => $recurring_invoice->load('invoices','subscription'), | ||||||
|  |             'subscription' => $recurring_invoice->subscription | ||||||
|  |         ]); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
| } | } | ||||||
|  | |||||||
| @ -31,9 +31,12 @@ class SubscriptionPlanSwitchController extends Controller | |||||||
|      */ |      */ | ||||||
|     public function index(ShowPlanSwitchRequest $request, RecurringInvoice $recurring_invoice, Subscription $target) |     public function index(ShowPlanSwitchRequest $request, RecurringInvoice $recurring_invoice, Subscription $target) | ||||||
|     { |     { | ||||||
|  | 
 | ||||||
|         $amount = $recurring_invoice->subscription |         $amount = $recurring_invoice->subscription | ||||||
|                                     ->service() |                                     ->service() | ||||||
|                                     ->calculateUpgradePrice($recurring_invoice, $target); |                                     ->calculateUpgradePriceV2($recurring_invoice, $target); | ||||||
|  | 
 | ||||||
|  |         nlog("payment amount = {$amount}"); | ||||||
|         /** |         /** | ||||||
|          * Null value here is a proxy for |          * Null value here is a proxy for | ||||||
|          * denying the user a change plan option |          * denying the user a change plan option | ||||||
| @ -42,11 +45,14 @@ class SubscriptionPlanSwitchController extends Controller | |||||||
|             render('subscriptions.denied'); |             render('subscriptions.denied'); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  |         $amount = max(0,$amount); | ||||||
|  | 
 | ||||||
|         return render('subscriptions.switch', [ |         return render('subscriptions.switch', [ | ||||||
|             'subscription' => $recurring_invoice->subscription, |             'subscription' => $recurring_invoice->subscription, | ||||||
|             'recurring_invoice' => $recurring_invoice, |             'recurring_invoice' => $recurring_invoice, | ||||||
|             'target' => $target, |             'target' => $target, | ||||||
|             'amount' => $amount, |             'amount' => $amount, | ||||||
|         ]); |         ]); | ||||||
|  |          | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | |||||||
| @ -53,6 +53,16 @@ class SubscriptionPurchaseController extends Controller | |||||||
|             $this->setLocale($request->query('locale')); |             $this->setLocale($request->query('locale')); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  |         if(!auth()->guard('contact')->check() && $subscription->registration_required && $subscription->company->client_can_register) { | ||||||
|  | 
 | ||||||
|  |             session()->put('url.intended', route('client.subscription.upgrade',['subscription' => $subscription->hashed_id])); | ||||||
|  | 
 | ||||||
|  |             return redirect()->route('client.register', ['company_key' => $subscription->company->company_key]); | ||||||
|  |         } | ||||||
|  |         elseif(!auth()->guard('contact')->check() && $subscription->registration_required && ! $subscription->company->client_can_register) { | ||||||
|  |             return render('generic.subscription_blocked', ['account' => $subscription->company->account, 'company' => $subscription->company]); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|         return view('billing-portal.purchasev2', [ |         return view('billing-portal.purchasev2', [ | ||||||
|             'subscription' => $subscription, |             'subscription' => $subscription, | ||||||
|             'hash' => Str::uuid()->toString(), |             'hash' => Str::uuid()->toString(), | ||||||
|  | |||||||
| @ -521,7 +521,7 @@ class CompanyController extends BaseController | |||||||
|             $nmo->company = $other_company; |             $nmo->company = $other_company; | ||||||
|             $nmo->settings = $other_company->settings; |             $nmo->settings = $other_company->settings; | ||||||
|             $nmo->to_user = auth()->user(); |             $nmo->to_user = auth()->user(); | ||||||
|             NinjaMailerJob::dispatch($nmo, true); |             (new NinjaMailerJob($nmo, true))->handle(); | ||||||
| 
 | 
 | ||||||
|             $company->delete(); |             $company->delete(); | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -12,12 +12,14 @@ | |||||||
| namespace App\Http\Controllers; | namespace App\Http\Controllers; | ||||||
| 
 | 
 | ||||||
| use App\Factory\ExpenseCategoryFactory; | use App\Factory\ExpenseCategoryFactory; | ||||||
|  | use App\Filters\ExpenseCategoryFilters; | ||||||
| use App\Http\Requests\ExpenseCategory\CreateExpenseCategoryRequest; | use App\Http\Requests\ExpenseCategory\CreateExpenseCategoryRequest; | ||||||
| use App\Http\Requests\ExpenseCategory\DestroyExpenseCategoryRequest; | use App\Http\Requests\ExpenseCategory\DestroyExpenseCategoryRequest; | ||||||
| use App\Http\Requests\ExpenseCategory\EditExpenseCategoryRequest; | use App\Http\Requests\ExpenseCategory\EditExpenseCategoryRequest; | ||||||
| use App\Http\Requests\ExpenseCategory\ShowExpenseCategoryRequest; | use App\Http\Requests\ExpenseCategory\ShowExpenseCategoryRequest; | ||||||
| use App\Http\Requests\ExpenseCategory\StoreExpenseCategoryRequest; | use App\Http\Requests\ExpenseCategory\StoreExpenseCategoryRequest; | ||||||
| use App\Http\Requests\ExpenseCategory\UpdateExpenseCategoryRequest; | use App\Http\Requests\ExpenseCategory\UpdateExpenseCategoryRequest; | ||||||
|  | use App\Models\Expense; | ||||||
| use App\Models\ExpenseCategory; | use App\Models\ExpenseCategory; | ||||||
| use App\Repositories\BaseRepository; | use App\Repositories\BaseRepository; | ||||||
| use App\Transformers\ExpenseCategoryTransformer; | use App\Transformers\ExpenseCategoryTransformer; | ||||||
| @ -79,13 +81,15 @@ class ExpenseCategoryController extends BaseController | |||||||
|      * |      * | ||||||
|      * @return Response |      * @return Response | ||||||
|      */ |      */ | ||||||
|     public function index() |     public function index(ExpenseCategoryFilters $filters) | ||||||
|     { |     { | ||||||
|         $expense_categories = ExpenseCategory::scope(); |         $expense_categories = ExpenseCategory::filter($filters); | ||||||
| 
 | 
 | ||||||
|         return $this->listResponse($expense_categories); |         return $this->listResponse($expense_categories); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|     /** |     /** | ||||||
|      * Show the form for creating a new resource. |      * Show the form for creating a new resource. | ||||||
|      * |      * | ||||||
| @ -131,11 +135,45 @@ class ExpenseCategoryController extends BaseController | |||||||
|         return $this->itemResponse($expense_category); |         return $this->itemResponse($expense_category); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | 
 | ||||||
|     /** |     /** | ||||||
|      * Store a newly created resource in storage. |      * Store a newly created resource in storage. | ||||||
|      * |      * | ||||||
|      * @param StoreExpenseCategoryRequest $request |      * @param StoreInvoiceRequest $request  The request | ||||||
|  |      * | ||||||
|      * @return Response |      * @return Response | ||||||
|  |      * | ||||||
|  |      * | ||||||
|  |      * @OA\Post( | ||||||
|  |      *      path="/api/v1/expense_categories", | ||||||
|  |      *      operationId="storeExpenseCategory", | ||||||
|  |      *      tags={"expense_categories"}, | ||||||
|  |      *      summary="Adds a expense category", | ||||||
|  |      *      description="Adds an expense category to the system", | ||||||
|  |      *      @OA\Parameter(ref="#/components/parameters/X-Api-Secret"), | ||||||
|  |      *      @OA\Parameter(ref="#/components/parameters/X-Api-Token"), | ||||||
|  |      *      @OA\Parameter(ref="#/components/parameters/X-Requested-With"), | ||||||
|  |      *      @OA\Parameter(ref="#/components/parameters/include"), | ||||||
|  |      *      @OA\Response( | ||||||
|  |      *          response=200, | ||||||
|  |      *          description="Returns the saved invoice object", | ||||||
|  |      *          @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/ExpenseCategory"), | ||||||
|  |      *       ), | ||||||
|  |      *       @OA\Response( | ||||||
|  |      *          response=422, | ||||||
|  |      *          description="Validation error", | ||||||
|  |      *          @OA\JsonContent(ref="#/components/schemas/ValidationError"), | ||||||
|  |      * | ||||||
|  |      *       ), | ||||||
|  |      *       @OA\Response( | ||||||
|  |      *           response="default", | ||||||
|  |      *           description="Unexpected Error", | ||||||
|  |      *           @OA\JsonContent(ref="#/components/schemas/Error"), | ||||||
|  |      *       ), | ||||||
|  |      *     ) | ||||||
|      */ |      */ | ||||||
|     public function store(StoreExpenseCategoryRequest $request) |     public function store(StoreExpenseCategoryRequest $request) | ||||||
|     { |     { | ||||||
|  | |||||||
| @ -13,7 +13,6 @@ namespace App\Http\Controllers; | |||||||
| 
 | 
 | ||||||
| use App\Http\Requests\Import\ImportRequest; | use App\Http\Requests\Import\ImportRequest; | ||||||
| use App\Http\Requests\Import\PreImportRequest; | use App\Http\Requests\Import\PreImportRequest; | ||||||
| use App\Jobs\Import\CSVImport; |  | ||||||
| use App\Jobs\Import\CSVIngest; | use App\Jobs\Import\CSVIngest; | ||||||
| use Illuminate\Http\UploadedFile; | use Illuminate\Http\UploadedFile; | ||||||
| use Illuminate\Support\Facades\Cache; | use Illuminate\Support\Facades\Cache; | ||||||
| @ -162,7 +161,7 @@ class ImportController extends Controller | |||||||
|     public function detectDelimiter($csvfile) |     public function detectDelimiter($csvfile) | ||||||
|     { |     { | ||||||
|         $delimiters = array(',', '.', ';'); |         $delimiters = array(',', '.', ';'); | ||||||
|         $bestDelimiter = false; |         $bestDelimiter = ' '; | ||||||
|         $count = 0; |         $count = 0; | ||||||
|         foreach ($delimiters as $delimiter) |         foreach ($delimiters as $delimiter) | ||||||
|             if (substr_count($csvfile, $delimiter) > $count) { |             if (substr_count($csvfile, $delimiter) > $count) { | ||||||
|  | |||||||
| @ -781,7 +781,8 @@ class InvoiceController extends BaseController | |||||||
|             case 'email': |             case 'email': | ||||||
|                 //check query parameter for email_type and set the template else use calculateTemplate
 |                 //check query parameter for email_type and set the template else use calculateTemplate
 | ||||||
| 
 | 
 | ||||||
|                 if (request()->has('email_type') && in_array(request()->input('email_type'), ['reminder1', 'reminder2', 'reminder3', 'reminder_endless', 'custom1', 'custom2', 'custom3'])) { |                 // if (request()->has('email_type') && in_array(request()->input('email_type'), ['reminder1', 'reminder2', 'reminder3', 'reminder_endless', 'custom1', 'custom2', 'custom3'])) {
 | ||||||
|  |                 if (request()->has('email_type') && property_exists($invoice->company->settings, request()->input('email_type'))) { | ||||||
|                     $this->reminder_template = $invoice->client->getSetting(request()->input('email_type')); |                     $this->reminder_template = $invoice->client->getSetting(request()->input('email_type')); | ||||||
|                 } else { |                 } else { | ||||||
|                     $this->reminder_template = $invoice->calculateTemplate('invoice'); |                     $this->reminder_template = $invoice->calculateTemplate('invoice'); | ||||||
|  | |||||||
| @ -18,6 +18,10 @@ class PaymentWebhookController extends Controller | |||||||
| { | { | ||||||
|     public function __invoke(PaymentWebhookRequest $request) |     public function __invoke(PaymentWebhookRequest $request) | ||||||
|     { |     { | ||||||
|  |         //return early if we cannot resolve the company gateway
 | ||||||
|  |         if(!$request->getCompanyGateway()) | ||||||
|  |             return response()->json([], 200); | ||||||
|  | 
 | ||||||
|         return $request |         return $request | ||||||
|             ->getCompanyGateway() |             ->getCompanyGateway() | ||||||
|             ->driver() |             ->driver() | ||||||
|  | |||||||
| @ -74,7 +74,7 @@ class PostMarkController extends BaseController | |||||||
|      */ |      */ | ||||||
|     public function webhook(Request $request) |     public function webhook(Request $request) | ||||||
|     { |     { | ||||||
|         if ($request->header('X-API-SECURITY') && $request->header('X-API-SECURITY') == config('postmark.secret')) { |         if ($request->header('X-API-SECURITY') && $request->header('X-API-SECURITY') == config('services.postmark.token')) { | ||||||
|             ProcessPostmarkWebhook::dispatch($request->all()); |             ProcessPostmarkWebhook::dispatch($request->all()); | ||||||
| 
 | 
 | ||||||
|             return response()->json(['message' => 'Success'], 200); |             return response()->json(['message' => 'Success'], 200); | ||||||
|  | |||||||
| @ -198,7 +198,7 @@ class PurchaseOrderController extends BaseController | |||||||
|              |              | ||||||
|         event(new PurchaseOrderWasCreated($purchase_order, $purchase_order->company, Ninja::eventVars(auth()->user() ? auth()->user()->id : null))); |         event(new PurchaseOrderWasCreated($purchase_order, $purchase_order->company, Ninja::eventVars(auth()->user() ? auth()->user()->id : null))); | ||||||
| 
 | 
 | ||||||
|         return $this->itemResponse($purchase_order); |         return $this->itemResponse($purchase_order->fresh()); | ||||||
|     } |     } | ||||||
|     /** |     /** | ||||||
|      * Display the specified resource. |      * Display the specified resource. | ||||||
| @ -502,7 +502,6 @@ class PurchaseOrderController extends BaseController | |||||||
|         /* |         /* | ||||||
|          * Download Purchase Order/s |          * Download Purchase Order/s | ||||||
|          */ |          */ | ||||||
| 
 |  | ||||||
|         if ($action == 'bulk_download' && $purchase_orders->count() >= 1) { |         if ($action == 'bulk_download' && $purchase_orders->count() >= 1) { | ||||||
|             $purchase_orders->each(function ($purchase_order) { |             $purchase_orders->each(function ($purchase_order) { | ||||||
|                 if (auth()->user()->cannot('view', $purchase_order)) { |                 if (auth()->user()->cannot('view', $purchase_order)) { | ||||||
|  | |||||||
| @ -0,0 +1,89 @@ | |||||||
|  | <?php | ||||||
|  | /** | ||||||
|  |  * Invoice Ninja (https://invoiceninja.com). | ||||||
|  |  * | ||||||
|  |  * @link https://github.com/invoiceninja/invoiceninja source repository | ||||||
|  |  * | ||||||
|  |  * @copyright Copyright (c) 2022. Invoice Ninja LLC (https://invoiceninja.com) | ||||||
|  |  * | ||||||
|  |  * @license https://www.elastic.co/licensing/elastic-license | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | namespace App\Http\Controllers\Reports; | ||||||
|  | 
 | ||||||
|  | use App\Export\CSV\ProductExport; | ||||||
|  | use App\Export\CSV\ProductSalesExport; | ||||||
|  | use App\Http\Controllers\BaseController; | ||||||
|  | use App\Http\Requests\Report\GenericReportRequest; | ||||||
|  | use App\Http\Requests\Report\ProductSalesReportRequest; | ||||||
|  | use App\Jobs\Report\SendToAdmin; | ||||||
|  | use App\Models\Client; | ||||||
|  | use App\Utils\Traits\MakesHash; | ||||||
|  | use Illuminate\Http\Response; | ||||||
|  | 
 | ||||||
|  | class ProductSalesReportController extends BaseController | ||||||
|  | { | ||||||
|  |     use MakesHash; | ||||||
|  | 
 | ||||||
|  |     private string $filename = 'product_sales.csv'; | ||||||
|  | 
 | ||||||
|  |     public function __construct() | ||||||
|  |     { | ||||||
|  |         parent::__construct(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * @OA\Post( | ||||||
|  |      *      path="/api/v1/reports/product_sales", | ||||||
|  |      *      operationId="getProductSalesReport", | ||||||
|  |      *      tags={"reports"}, | ||||||
|  |      *      summary="Product Salesreports", | ||||||
|  |      *      description="Export product sales reports", | ||||||
|  |      *      @OA\Parameter(ref="#/components/parameters/X-Api-Secret"), | ||||||
|  |      *      @OA\Parameter(ref="#/components/parameters/X-Requested-With"), | ||||||
|  |      *      @OA\RequestBody( | ||||||
|  |      *          required=true, | ||||||
|  |      *          @OA\JsonContent(ref="#/components/schemas/GenericReportSchema") | ||||||
|  |      *      ), | ||||||
|  |      *      @OA\Response( | ||||||
|  |      *          response=200, | ||||||
|  |      *          description="success", | ||||||
|  |      *          @OA\Header(header="X-MINIMUM-CLIENT-VERSION", ref="#/components/headers/X-MINIMUM-CLIENT-VERSION"), | ||||||
|  |      *          @OA\Header(header="X-RateLimit-Remaining", ref="#/components/headers/X-RateLimit-Remaining"), | ||||||
|  |      *          @OA\Header(header="X-RateLimit-Limit", ref="#/components/headers/X-RateLimit-Limit"), | ||||||
|  |      *       ), | ||||||
|  |      *       @OA\Response( | ||||||
|  |      *          response=422, | ||||||
|  |      *          description="Validation error", | ||||||
|  |      *          @OA\JsonContent(ref="#/components/schemas/ValidationError"), | ||||||
|  |      *       ), | ||||||
|  |      *       @OA\Response( | ||||||
|  |      *           response="default", | ||||||
|  |      *           description="Unexpected Error", | ||||||
|  |      *           @OA\JsonContent(ref="#/components/schemas/Error"), | ||||||
|  |      *       ), | ||||||
|  |      *     ) | ||||||
|  |      */ | ||||||
|  |     public function __invoke(ProductSalesReportRequest $request) | ||||||
|  |     { | ||||||
|  |         if ($request->has('send_email') && $request->get('send_email')) { | ||||||
|  |             SendToAdmin::dispatch(auth()->user()->company(), $request->all(), ProductSalesExport::class, $this->filename); | ||||||
|  | 
 | ||||||
|  |             return response()->json(['message' => 'working...'], 200); | ||||||
|  |         } | ||||||
|  |         // expect a list of visible fields, or use the default
 | ||||||
|  | 
 | ||||||
|  |         $export = new ProductSalesExport(auth()->user()->company(), $request->all()); | ||||||
|  | 
 | ||||||
|  |         $csv = $export->run(); | ||||||
|  | 
 | ||||||
|  |         $headers = [ | ||||||
|  |             'Content-Disposition' => 'attachment', | ||||||
|  |             'Content-Type' => 'text/csv', | ||||||
|  |         ]; | ||||||
|  | 
 | ||||||
|  |         return response()->streamDownload(function () use ($csv) { | ||||||
|  |             echo $csv; | ||||||
|  |         }, $this->filename, $headers); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -1,4 +1,13 @@ | |||||||
| <?php | <?php | ||||||
|  | /** | ||||||
|  |  * Invoice Ninja (https://invoiceninja.com). | ||||||
|  |  * | ||||||
|  |  * @link https://github.com/invoiceninja/invoiceninja source repository | ||||||
|  |  * | ||||||
|  |  * @copyright Copyright (c) 2022. Invoice Ninja LLC (https://invoiceninja.com) | ||||||
|  |  * | ||||||
|  |  * @license https://www.elastic.co/licensing/elastic-license | ||||||
|  |  */ | ||||||
| 
 | 
 | ||||||
| namespace App\Http\Controllers; | namespace App\Http\Controllers; | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -15,6 +15,7 @@ namespace App\Http\Controllers; | |||||||
| use App\Events\Subscription\SubscriptionWasCreated; | use App\Events\Subscription\SubscriptionWasCreated; | ||||||
| use App\Events\Subscription\SubscriptionWasUpdated; | use App\Events\Subscription\SubscriptionWasUpdated; | ||||||
| use App\Factory\SubscriptionFactory; | use App\Factory\SubscriptionFactory; | ||||||
|  | use App\Filters\SubscriptionFilters; | ||||||
| use App\Http\Requests\Subscription\CreateSubscriptionRequest; | use App\Http\Requests\Subscription\CreateSubscriptionRequest; | ||||||
| use App\Http\Requests\Subscription\DestroySubscriptionRequest; | use App\Http\Requests\Subscription\DestroySubscriptionRequest; | ||||||
| use App\Http\Requests\Subscription\EditSubscriptionRequest; | use App\Http\Requests\Subscription\EditSubscriptionRequest; | ||||||
| @ -80,9 +81,9 @@ class SubscriptionController extends BaseController | |||||||
|      *       ), |      *       ), | ||||||
|      *     ) |      *     ) | ||||||
|      */ |      */ | ||||||
|     public function index(): \Illuminate\Http\Response |     public function index(SubscriptionFilters $filters): \Illuminate\Http\Response | ||||||
|     { |     { | ||||||
|         $subscriptions = Subscription::query()->company(); |         $subscriptions = Subscription::filter($filters); | ||||||
| 
 | 
 | ||||||
|         return $this->listResponse($subscriptions); |         return $this->listResponse($subscriptions); | ||||||
|     } |     } | ||||||
|  | |||||||
| @ -11,37 +11,40 @@ | |||||||
| 
 | 
 | ||||||
| namespace App\Http\Controllers; | namespace App\Http\Controllers; | ||||||
| 
 | 
 | ||||||
| use App\Http\Requests\TaskScheduler\CreateScheduledTaskRequest; | use App\Factory\SchedulerFactory; | ||||||
| use App\Http\Requests\TaskScheduler\UpdateScheduleRequest; | use App\Http\Requests\TaskScheduler\CreateSchedulerRequest; | ||||||
|  | use App\Http\Requests\TaskScheduler\ShowSchedulerRequest; | ||||||
|  | use App\Http\Requests\TaskScheduler\StoreSchedulerRequest; | ||||||
|  | use App\Http\Requests\TaskScheduler\UpdateSchedulerRequest; | ||||||
|  | use App\Http\Requests\Task\DestroySchedulerRequest; | ||||||
| use App\Jobs\Ninja\TaskScheduler; | use App\Jobs\Ninja\TaskScheduler; | ||||||
| use App\Jobs\Report\ProfitAndLoss; | use App\Jobs\Report\ProfitAndLoss; | ||||||
| use App\Models\Scheduler; | use App\Models\Scheduler; | ||||||
| use App\Repositories\TaskSchedulerRepository; | use App\Repositories\SchedulerRepository; | ||||||
| use App\Transformers\TaskSchedulerTransformer; | use App\Transformers\SchedulerTransformer; | ||||||
|  | use App\Utils\Traits\MakesHash; | ||||||
| use Carbon\Carbon; | use Carbon\Carbon; | ||||||
| use Illuminate\Database\Eloquent\Model; | use Illuminate\Database\Eloquent\Model; | ||||||
| use Symfony\Component\HttpFoundation\Request; | use Symfony\Component\HttpFoundation\Request; | ||||||
| 
 | 
 | ||||||
| class TaskSchedulerController extends BaseController | class TaskSchedulerController extends BaseController | ||||||
| { | { | ||||||
|  |     use MakesHash; | ||||||
|  | 
 | ||||||
|     protected $entity_type = Scheduler::class; |     protected $entity_type = Scheduler::class; | ||||||
| 
 | 
 | ||||||
|     protected $entity_transformer = TaskSchedulerTransformer::class; |     protected $entity_transformer = SchedulerTransformer::class; | ||||||
| 
 | 
 | ||||||
|     protected TaskSchedulerRepository $scheduler_repository; |     public function __construct(protected SchedulerRepository $scheduler_repository) | ||||||
| 
 |  | ||||||
|     public function __construct(TaskSchedulerRepository $scheduler_repository) |  | ||||||
|     { |     { | ||||||
|         parent::__construct(); |         parent::__construct(); | ||||||
| 
 |  | ||||||
|         $this->scheduler_repository = $scheduler_repository; |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /** |     /** | ||||||
|      * @OA\GET( |      * @OA\GET( | ||||||
|      *      path="/api/v1/task_scheduler/", |      *      path="/api/v1/task_schedulers/", | ||||||
|      *      operationId="getTaskSchedulers", |      *      operationId="getTaskSchedulers", | ||||||
|      *      tags={"task_scheduler"}, |      *      tags={"task_schedulers"}, | ||||||
|      *      summary="Task Scheduler Index", |      *      summary="Task Scheduler Index", | ||||||
|      *      description="Get all schedulers with associated jobs", |      *      description="Get all schedulers with associated jobs", | ||||||
|      *      @OA\Parameter(ref="#/components/parameters/X-Api-Secret"), |      *      @OA\Parameter(ref="#/components/parameters/X-Api-Secret"), | ||||||
| @ -67,11 +70,57 @@ class TaskSchedulerController extends BaseController | |||||||
|         return $this->listResponse($schedulers); |         return $this->listResponse($schedulers); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     /** | ||||||
|  |      * Show the form for creating a new resource. | ||||||
|  |      * | ||||||
|  |      * @param CreateSchedulerRequest $request  The request | ||||||
|  |      * | ||||||
|  |      * @return Response | ||||||
|  |      * | ||||||
|  |      * | ||||||
|  |      * @OA\Get( | ||||||
|  |      *      path="/api/v1/invoices/task_schedulers", | ||||||
|  |      *      operationId="getTaskScheduler", | ||||||
|  |      *      tags={"task_schedulers"}, | ||||||
|  |      *      summary="Gets a new blank scheduler object", | ||||||
|  |      *      description="Returns a blank object with default values", | ||||||
|  |      *      @OA\Parameter(ref="#/components/parameters/X-Api-Secret"), | ||||||
|  |      *      @OA\Parameter(ref="#/components/parameters/X-Api-Token"), | ||||||
|  |      *      @OA\Parameter(ref="#/components/parameters/X-Requested-With"), | ||||||
|  |      *      @OA\Parameter(ref="#/components/parameters/include"), | ||||||
|  |      *      @OA\Response( | ||||||
|  |      *          response=200, | ||||||
|  |      *          description="A blank scheduler object", | ||||||
|  |      *          @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/TaskSchedulerSchema"), | ||||||
|  |      *       ), | ||||||
|  |      *       @OA\Response( | ||||||
|  |      *          response=422, | ||||||
|  |      *          description="Validation error", | ||||||
|  |      *          @OA\JsonContent(ref="#/components/schemas/ValidationError"), | ||||||
|  |      * | ||||||
|  |      *       ), | ||||||
|  |      *       @OA\Response( | ||||||
|  |      *           response="default", | ||||||
|  |      *           description="Unexpected Error", | ||||||
|  |      *           @OA\JsonContent(ref="#/components/schemas/Error"), | ||||||
|  |      *       ), | ||||||
|  |      *     ) | ||||||
|  |      */ | ||||||
|  |     public function create(CreateSchedulerRequest $request) | ||||||
|  |     { | ||||||
|  |         $scheduler = SchedulerFactory::create(auth()->user()->company()->id, auth()->user()->id); | ||||||
|  | 
 | ||||||
|  |         return $this->itemResponse($scheduler); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     /** |     /** | ||||||
|      * @OA\Post( |      * @OA\Post( | ||||||
|      *      path="/api/v1/task_scheduler/", |      *      path="/api/v1/task_schedulers/", | ||||||
|      *      operationId="createTaskScheduler", |      *      operationId="createTaskScheduler", | ||||||
|      *      tags={"task_scheduler"}, |      *      tags={"task_schedulers"}, | ||||||
|      *      summary="Create task scheduler with job ", |      *      summary="Create task scheduler with job ", | ||||||
|      *      description="Create task scheduler with a job (action(job) request should be sent via request also. Example: We want client report to be job which will be run
 |      *      description="Create task scheduler with a job (action(job) request should be sent via request also. Example: We want client report to be job which will be run
 | ||||||
|      * multiple times, we should send the same parameters in the request as we would send if we wanted to get report, see example",
 |      * multiple times, we should send the same parameters in the request as we would send if we wanted to get report, see example",
 | ||||||
| @ -100,19 +149,18 @@ class TaskSchedulerController extends BaseController | |||||||
|      *       ), |      *       ), | ||||||
|      *     ) |      *     ) | ||||||
|      */ |      */ | ||||||
|     public function store(CreateScheduledTaskRequest $request) |     public function store(StoreSchedulerRequest $request) | ||||||
|     { |     { | ||||||
|         $scheduler = new Scheduler(); |         $scheduler = $this->scheduler_repository->save($request->all(), SchedulerFactory::create(auth()->user()->company()->id, auth()->user()->id)); | ||||||
|         $scheduler->service()->store($scheduler, $request); |  | ||||||
| 
 | 
 | ||||||
|         return $this->itemResponse($scheduler); |         return $this->itemResponse($scheduler); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /** |     /** | ||||||
|      * @OA\GET( |      * @OA\GET( | ||||||
|      *      path="/api/v1/task_scheduler/{id}", |      *      path="/api/v1/task_schedulers/{id}", | ||||||
|      *      operationId="showTaskScheduler", |      *      operationId="showTaskScheduler", | ||||||
|      *      tags={"task_scheduler"}, |      *      tags={"task_schedulers"}, | ||||||
|      *      summary="Show given scheduler", |      *      summary="Show given scheduler", | ||||||
|      *      description="Get scheduler with associated job", |      *      description="Get scheduler with associated job", | ||||||
|      *      @OA\Parameter(ref="#/components/parameters/X-Api-Secret"), |      *      @OA\Parameter(ref="#/components/parameters/X-Api-Secret"), | ||||||
| @ -142,16 +190,16 @@ class TaskSchedulerController extends BaseController | |||||||
|      *       ), |      *       ), | ||||||
|      *     ) |      *     ) | ||||||
|      */ |      */ | ||||||
|     public function show(Scheduler $scheduler) |     public function show(ShowSchedulerRequest $request, Scheduler $scheduler) | ||||||
|     { |     { | ||||||
|         return $this->itemResponse($scheduler); |         return $this->itemResponse($scheduler); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /** |     /** | ||||||
|      * @OA\PUT( |      * @OA\PUT( | ||||||
|      *      path="/api/v1/task_scheduler/{id}", |      *      path="/api/v1/task_schedulers/{id}", | ||||||
|      *      operationId="updateTaskScheduler", |      *      operationId="updateTaskScheduler", | ||||||
|      *      tags={"task_scheduler"}, |      *      tags={"task_schedulers"}, | ||||||
|      *      summary="Update task scheduler ", |      *      summary="Update task scheduler ", | ||||||
|      *      description="Update task scheduler", |      *      description="Update task scheduler", | ||||||
|      * @OA\Parameter(ref="#/components/parameters/X-Api-Secret"), |      * @OA\Parameter(ref="#/components/parameters/X-Api-Secret"), | ||||||
| @ -168,7 +216,7 @@ class TaskSchedulerController extends BaseController | |||||||
|      *          ), |      *          ), | ||||||
|      *      ),     * @OA\RequestBody( |      *      ),     * @OA\RequestBody( | ||||||
|      *          required=true, |      *          required=true, | ||||||
|      *          @OA\JsonContent(ref="#/components/schemas/UpdateTaskSchedulerSchema") |      *          @OA\JsonContent(ref="#/components/schemas/TaskSchedulerSchema") | ||||||
|      *      ), |      *      ), | ||||||
|      * @OA\Response( |      * @OA\Response( | ||||||
|      *          response=200, |      *          response=200, | ||||||
| @ -189,18 +237,18 @@ class TaskSchedulerController extends BaseController | |||||||
|      *       ), |      *       ), | ||||||
|      *     ) |      *     ) | ||||||
|      */ |      */ | ||||||
|     public function update(Scheduler $scheduler, UpdateScheduleRequest $request) |     public function update(UpdateSchedulerRequest $request, Scheduler $scheduler) | ||||||
|     { |     { | ||||||
|         $scheduler->service()->update($scheduler, $request); |         $this->scheduler_repository->save($request->all(), $scheduler); | ||||||
| 
 | 
 | ||||||
|         return $this->itemResponse($scheduler); |         return $this->itemResponse($scheduler); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /** |     /** | ||||||
|      * @OA\DELETE( |      * @OA\DELETE( | ||||||
|      *      path="/api/v1/task_scheduler/{id}", |      *      path="/api/v1/task_schedulers/{id}", | ||||||
|      *      operationId="destroyTaskScheduler", |      *      operationId="destroyTaskScheduler", | ||||||
|      *      tags={"task_scheduler"}, |      *      tags={"task_schedulers"}, | ||||||
|      *      summary="Destroy Task Scheduler", |      *      summary="Destroy Task Scheduler", | ||||||
|      *      description="Destroy task scheduler and its associated job", |      *      description="Destroy task scheduler and its associated job", | ||||||
|      *      @OA\Parameter(ref="#/components/parameters/X-Api-Secret"), |      *      @OA\Parameter(ref="#/components/parameters/X-Api-Secret"), | ||||||
| @ -230,10 +278,83 @@ class TaskSchedulerController extends BaseController | |||||||
|      *       ), |      *       ), | ||||||
|      *     ) |      *     ) | ||||||
|      */ |      */ | ||||||
|     public function destroy(Scheduler $scheduler) |     public function destroy(DestroySchedulerRequest $request, Scheduler $scheduler) | ||||||
|     { |     { | ||||||
|         $this->scheduler_repository->delete($scheduler); |         $this->scheduler_repository->delete($scheduler); | ||||||
| 
 | 
 | ||||||
|         return $this->itemResponse($scheduler->fresh()); |         return $this->itemResponse($scheduler->fresh()); | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * Perform bulk actions on the list view. | ||||||
|  |      * | ||||||
|  |      * @return Response | ||||||
|  |      * | ||||||
|  |      * | ||||||
|  |      * @OA\Post( | ||||||
|  |      *      path="/api/v1/task_schedulers/bulk", | ||||||
|  |      *      operationId="bulkTaskSchedulerActions", | ||||||
|  |      *      tags={"task_schedulers"}, | ||||||
|  |      *      summary="Performs bulk actions on an array of task_schedulers", | ||||||
|  |      *      description="", | ||||||
|  |      *      @OA\Parameter(ref="#/components/parameters/X-Api-Secret"), | ||||||
|  |      *      @OA\Parameter(ref="#/components/parameters/X-Api-Token"), | ||||||
|  |      *      @OA\Parameter(ref="#/components/parameters/X-Requested-With"), | ||||||
|  |      *      @OA\Parameter(ref="#/components/parameters/index"), | ||||||
|  |      *      @OA\RequestBody( | ||||||
|  |      *         description="array of ids", | ||||||
|  |      *         required=true, | ||||||
|  |      *         @OA\MediaType( | ||||||
|  |      *             mediaType="application/json", | ||||||
|  |      *             @OA\Schema( | ||||||
|  |      *                 type="array", | ||||||
|  |      *                 @OA\Items( | ||||||
|  |      *                     type="integer", | ||||||
|  |      *                     description="Array of hashed IDs to be bulk 'actioned", | ||||||
|  |      *                     example="[0,1,2,3]", | ||||||
|  |      *                 ), | ||||||
|  |      *             ) | ||||||
|  |      *         ) | ||||||
|  |      *     ), | ||||||
|  |      *      @OA\Response( | ||||||
|  |      *          response=200, | ||||||
|  |      *          description="The TaskSchedule response", | ||||||
|  |      *          @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/TaskScheduleSchema"), | ||||||
|  |      *       ), | ||||||
|  |      *       @OA\Response( | ||||||
|  |      *          response=422, | ||||||
|  |      *          description="Validation error", | ||||||
|  |      *          @OA\JsonContent(ref="#/components/schemas/ValidationError"), | ||||||
|  |      *       ), | ||||||
|  |      *       @OA\Response( | ||||||
|  |      *           response="default", | ||||||
|  |      *           description="Unexpected Error", | ||||||
|  |      *           @OA\JsonContent(ref="#/components/schemas/Error"), | ||||||
|  |      *       ), | ||||||
|  |      *     ) | ||||||
|  |      */ | ||||||
|  |     public function bulk() | ||||||
|  |     { | ||||||
|  |         $action = request()->input('action'); | ||||||
|  | 
 | ||||||
|  |         if(!in_array($action, ['archive', 'restore', 'delete'])) | ||||||
|  |             return response()->json(['message' => 'Bulk action does not exist'], 400); | ||||||
|  | 
 | ||||||
|  |         $ids = request()->input('ids'); | ||||||
|  | 
 | ||||||
|  |         $task_schedulers = Scheduler::withTrashed()->find($this->transformKeys($ids)); | ||||||
|  | 
 | ||||||
|  |         $task_schedulers->each(function ($task_scheduler, $key) use ($action) { | ||||||
|  |             if (auth()->user()->can('edit', $task_scheduler)) { | ||||||
|  |                 $this->scheduler_repository->{$action}($task_scheduler); | ||||||
|  |             } | ||||||
|  |         }); | ||||||
|  | 
 | ||||||
|  |         return $this->listResponse(Scheduler::withTrashed()->whereIn('id', $this->transformKeys($ids))); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
| } | } | ||||||
|  | |||||||
| @ -174,6 +174,8 @@ class BillingPortalPurchase extends Component | |||||||
|      */ |      */ | ||||||
|     public $company; |     public $company; | ||||||
| 
 | 
 | ||||||
|  |     public $db; | ||||||
|  | 
 | ||||||
|     /** |     /** | ||||||
|      * Campaign reference. |      * Campaign reference. | ||||||
|      * |      * | ||||||
| @ -183,7 +185,11 @@ class BillingPortalPurchase extends Component | |||||||
| 
 | 
 | ||||||
|     public function mount() |     public function mount() | ||||||
|     { |     { | ||||||
|         MultiDB::setDb($this->company->db); |         MultiDB::setDb($this->db); | ||||||
|  | 
 | ||||||
|  |         $this->subscription = Subscription::with('company')->find($this->subscription); | ||||||
|  | 
 | ||||||
|  |         $this->company = $this->subscription->company; | ||||||
| 
 | 
 | ||||||
|         $this->quantity = 1; |         $this->quantity = 1; | ||||||
| 
 | 
 | ||||||
| @ -196,6 +202,12 @@ class BillingPortalPurchase extends Component | |||||||
|         elseif(strlen($this->subscription->promo_code) == 0 && $this->subscription->promo_discount > 0){ |         elseif(strlen($this->subscription->promo_code) == 0 && $this->subscription->promo_discount > 0){ | ||||||
|             $this->price = $this->subscription->promo_price; |             $this->price = $this->subscription->promo_price; | ||||||
|         } |         } | ||||||
|  | 
 | ||||||
|  |         /* Leave this here, otherwise a logged in user will need to reauth... painfully */ | ||||||
|  |         if(Auth::guard('contact')->check()){ | ||||||
|  |             return $this->getPaymentMethods(auth()->guard('contact')->user()); | ||||||
|  |         } | ||||||
|  |          | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /** |     /** | ||||||
| @ -225,10 +237,10 @@ class BillingPortalPurchase extends Component | |||||||
| 
 | 
 | ||||||
|         $this->steps['existing_user'] = false; |         $this->steps['existing_user'] = false; | ||||||
| 
 | 
 | ||||||
|         $contact = $this->createBlankClient(); |         $this->contact = $this->createBlankClient(); | ||||||
| 
 | 
 | ||||||
|         if ($contact && $contact instanceof ClientContact) { |         if ($this->contact && $this->contact instanceof ClientContact) { | ||||||
|             $this->getPaymentMethods($contact); |             $this->getPaymentMethods($this->contact); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| @ -265,9 +277,6 @@ class BillingPortalPurchase extends Component | |||||||
|             } |             } | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
| // nlog($this->subscription->group_settings->settings);
 |  | ||||||
| // nlog($this->subscription->group_settings->settings->currency_id);
 |  | ||||||
| 
 |  | ||||||
|         if(array_key_exists('currency_id', $this->request_data)) { |         if(array_key_exists('currency_id', $this->request_data)) { | ||||||
| 
 | 
 | ||||||
|             $currency = Cache::get('currencies')->filter(function ($item){ |             $currency = Cache::get('currencies')->filter(function ($item){ | ||||||
|  | |||||||
| @ -15,6 +15,7 @@ use App\DataMapper\ClientSettings; | |||||||
| use App\Factory\ClientFactory; | use App\Factory\ClientFactory; | ||||||
| use App\Jobs\Mail\NinjaMailerJob; | use App\Jobs\Mail\NinjaMailerJob; | ||||||
| use App\Jobs\Mail\NinjaMailerObject; | use App\Jobs\Mail\NinjaMailerObject; | ||||||
|  | use App\Jobs\Subscription\CleanStaleInvoiceOrder; | ||||||
| use App\Libraries\MultiDB; | use App\Libraries\MultiDB; | ||||||
| use App\Mail\ContactPasswordlessLogin; | use App\Mail\ContactPasswordlessLogin; | ||||||
| use App\Mail\Subscription\OtpCode; | use App\Mail\Subscription\OtpCode; | ||||||
| @ -120,7 +121,7 @@ class BillingPortalPurchasev2 extends Component | |||||||
|      * |      * | ||||||
|      * @var array |      * @var array | ||||||
|      */ |      */ | ||||||
|     public $request_data; |     public $request_data = []; | ||||||
| 
 | 
 | ||||||
|     /** |     /** | ||||||
|      * Instance of company. |      * Instance of company. | ||||||
| @ -129,6 +130,14 @@ class BillingPortalPurchasev2 extends Component | |||||||
|      */ |      */ | ||||||
|     public $company; |     public $company; | ||||||
| 
 | 
 | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * Instance of company. | ||||||
|  |      * | ||||||
|  |      * @var string | ||||||
|  |      */ | ||||||
|  |     public string $db; | ||||||
|  | 
 | ||||||
|     /** |     /** | ||||||
|      * Campaign reference. |      * Campaign reference. | ||||||
|      * |      * | ||||||
| @ -151,10 +160,23 @@ class BillingPortalPurchasev2 extends Component | |||||||
|     public $valid_coupon = false; |     public $valid_coupon = false; | ||||||
|     public $payable_invoices = []; |     public $payable_invoices = []; | ||||||
|     public $payment_confirmed = false; |     public $payment_confirmed = false; | ||||||
|  |     public $is_eligible = true; | ||||||
|  |     public $not_eligible_message = ''; | ||||||
|      |      | ||||||
|     public function mount() |     public function mount() | ||||||
|     { |     { | ||||||
|         MultiDB::setDb($this->company->db); |         MultiDB::setDb($this->db); | ||||||
|  | 
 | ||||||
|  |         $this->subscription = Subscription::with('company')->find($this->subscription); | ||||||
|  | 
 | ||||||
|  |         $this->company = $this->subscription->company; | ||||||
|  | 
 | ||||||
|  |         if(auth()->guard('contact')->check()){ | ||||||
|  |             $this->email = auth()->guard('contact')->user()->email; | ||||||
|  |             $this->contact = auth()->guard('contact')->user(); | ||||||
|  |             $this->authenticated = true; | ||||||
|  |             $this->payment_started = true; | ||||||
|  |         } | ||||||
| 
 | 
 | ||||||
|         $this->discount = 0; |         $this->discount = 0; | ||||||
|         $this->sub_total = 0; |         $this->sub_total = 0; | ||||||
| @ -177,7 +199,7 @@ class BillingPortalPurchasev2 extends Component | |||||||
|             $this->coupon = request()->query('coupon'); |             $this->coupon = request()->query('coupon'); | ||||||
|             $this->handleCoupon(); |             $this->handleCoupon(); | ||||||
|         } |         } | ||||||
|         elseif(strlen($this->subscription->promo_code) == 0 && $this->subscription->promo_discount > 0){ |         elseif(isset($this->subscription->promo_code) && strlen($this->subscription->promo_code) == 0 && $this->subscription->promo_discount > 0){ | ||||||
|             $this->price = $this->subscription->promo_price;  |             $this->price = $this->subscription->promo_price;  | ||||||
|         } |         } | ||||||
|          |          | ||||||
| @ -224,6 +246,8 @@ class BillingPortalPurchasev2 extends Component | |||||||
| 
 | 
 | ||||||
|     public function resetEmail() |     public function resetEmail() | ||||||
|     { |     { | ||||||
|  |         $this->resetErrorBag('login'); | ||||||
|  |         $this->resetValidation('login');   | ||||||
|         $this->email = null; |         $this->email = null; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| @ -402,7 +426,6 @@ class BillingPortalPurchasev2 extends Component | |||||||
| 
 | 
 | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
| 
 |  | ||||||
|         return $this; |         return $this; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| @ -488,9 +511,20 @@ class BillingPortalPurchasev2 extends Component | |||||||
|      * |      * | ||||||
|      * @return void |      * @return void | ||||||
|      */ |      */ | ||||||
|     public function handleBeforePaymentEvents() :void |     public function handleBeforePaymentEvents() :self | ||||||
|     { |     { | ||||||
| 
 | 
 | ||||||
|  |         $eligibility_check = $this->subscription->service()->isEligible($this->contact); | ||||||
|  | 
 | ||||||
|  |         if(is_array($eligibility_check) && $eligibility_check['message'] != 'Success'){ | ||||||
|  |              | ||||||
|  |             $this->is_eligible = false; | ||||||
|  |             $this->not_eligible_message = $eligibility_check['message']; | ||||||
|  | 
 | ||||||
|  |             return $this; | ||||||
|  | 
 | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|         $data = [ |         $data = [ | ||||||
|             'client_id' => $this->contact->client->id, |             'client_id' => $this->contact->client->id, | ||||||
|             'date' => now()->format('Y-m-d'), |             'date' => now()->format('Y-m-d'), | ||||||
| @ -500,19 +534,9 @@ class BillingPortalPurchasev2 extends Component | |||||||
|             ]], |             ]], | ||||||
|             'user_input_promo_code' => $this->coupon, |             'user_input_promo_code' => $this->coupon, | ||||||
|             'coupon' => empty($this->subscription->promo_code) ? '' : $this->coupon, |             'coupon' => empty($this->subscription->promo_code) ? '' : $this->coupon, | ||||||
|             // 'quantity' => $this->quantity,
 | 
 | ||||||
|         ]; |         ]; | ||||||
| 
 | 
 | ||||||
|         $is_eligible = $this->subscription->service()->isEligible($this->contact); |  | ||||||
| 
 |  | ||||||
|         // if (is_array($is_eligible) && $is_eligible['message'] != 'Success') {
 |  | ||||||
|         //     $this->steps['not_eligible'] = true;
 |  | ||||||
|         //     $this->steps['not_eligible_message'] = $is_eligible['message'];
 |  | ||||||
|         //     $this->steps['show_loading_bar'] = false;
 |  | ||||||
| 
 |  | ||||||
|         //     return;
 |  | ||||||
|         // }
 |  | ||||||
| 
 |  | ||||||
|         $this->invoice = $this->subscription |         $this->invoice = $this->subscription | ||||||
|             ->service() |             ->service() | ||||||
|             ->createInvoiceV2($this->bundle, $this->contact->client_id, $this->valid_coupon) |             ->createInvoiceV2($this->bundle, $this->contact->client_id, $this->valid_coupon) | ||||||
| @ -533,9 +557,21 @@ class BillingPortalPurchasev2 extends Component | |||||||
|         ], now()->addMinutes(60)); |         ], now()->addMinutes(60)); | ||||||
| 
 | 
 | ||||||
|         $this->emit('beforePaymentEventsCompleted'); |         $this->emit('beforePaymentEventsCompleted'); | ||||||
|  | 
 | ||||||
|  |         return $this; | ||||||
|  | 
 | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| 
 |     public function handleTrial() | ||||||
|  |     { | ||||||
|  |         return $this->subscription->service()->startTrial([ | ||||||
|  |             'email' => $this->email ?? $this->contact->email, | ||||||
|  |             'quantity' => $this->quantity, | ||||||
|  |             'contact_id' => $this->contact->id, | ||||||
|  |             'client_id' => $this->contact->client->id, | ||||||
|  |             'bundle' => $this->bundle, | ||||||
|  |         ]); | ||||||
|  |     } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -13,6 +13,7 @@ | |||||||
| namespace App\Http\Livewire; | namespace App\Http\Livewire; | ||||||
| 
 | 
 | ||||||
| use App\Libraries\MultiDB; | use App\Libraries\MultiDB; | ||||||
|  | use App\Models\Company; | ||||||
| use App\Models\Credit; | use App\Models\Credit; | ||||||
| use App\Utils\Traits\WithSorting; | use App\Utils\Traits\WithSorting; | ||||||
| use Livewire\Component; | use Livewire\Component; | ||||||
| @ -23,26 +24,31 @@ class CreditsTable extends Component | |||||||
|     use WithPagination; |     use WithPagination; | ||||||
|     use WithSorting; |     use WithSorting; | ||||||
| 
 | 
 | ||||||
|     public $per_page = 10; |     public int $per_page = 10; | ||||||
| 
 | 
 | ||||||
|     public $company; |     public Company $company; | ||||||
|  | 
 | ||||||
|  |     public string $db; | ||||||
|  | 
 | ||||||
|  |     public int $company_id; | ||||||
| 
 | 
 | ||||||
|     public function mount() |     public function mount() | ||||||
|     { |     { | ||||||
|         MultiDB::setDb($this->company->db); |         MultiDB::setDb($this->db); | ||||||
|  | 
 | ||||||
|  |         $this->company = Company::find($this->company_id); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     public function render() |     public function render() | ||||||
|     { |     { | ||||||
|         $query = Credit::query() |         $query = Credit::query() | ||||||
|             ->where('client_id', auth()->guard('contact')->user()->client_id) |  | ||||||
|             ->where('company_id', $this->company->id) |             ->where('company_id', $this->company->id) | ||||||
|  |             ->where('client_id', auth()->guard('contact')->user()->client_id) | ||||||
|             ->where('status_id', '<>', Credit::STATUS_DRAFT) |             ->where('status_id', '<>', Credit::STATUS_DRAFT) | ||||||
|             ->where('is_deleted', 0) |             ->where('is_deleted', 0) | ||||||
|             ->where(function ($query) { |             ->where(function ($query) { | ||||||
|                 $query->whereDate('due_date', '>=', now()) |                 $query->whereDate('due_date', '>=', now()) | ||||||
|                       ->orWhereNull('due_date'); |                       ->orWhereNull('due_date'); | ||||||
|                 //->orWhere('due_date', '=', '');
 |  | ||||||
|             }) |             }) | ||||||
|             ->orderBy($this->sort_field, $this->sort_asc ? 'asc' : 'desc') |             ->orderBy($this->sort_field, $this->sort_asc ? 'asc' : 'desc') | ||||||
|             ->withTrashed() |             ->withTrashed() | ||||||
|  | |||||||
| @ -14,6 +14,7 @@ namespace App\Http\Livewire; | |||||||
| 
 | 
 | ||||||
| use App\Libraries\MultiDB; | use App\Libraries\MultiDB; | ||||||
| use App\Models\Client; | use App\Models\Client; | ||||||
|  | use App\Models\Company; | ||||||
| use App\Models\Credit; | use App\Models\Credit; | ||||||
| use App\Models\Document; | use App\Models\Document; | ||||||
| use App\Models\Expense; | use App\Models\Expense; | ||||||
| @ -31,21 +32,27 @@ class DocumentsTable extends Component | |||||||
| { | { | ||||||
|     use WithPagination, WithSorting; |     use WithPagination, WithSorting; | ||||||
| 
 | 
 | ||||||
|     public $client; |     public Company $company; | ||||||
| 
 | 
 | ||||||
|     public $per_page = 10; |     public Client $client; | ||||||
| 
 | 
 | ||||||
|     public $company; |     public int $client_id; | ||||||
|  | 
 | ||||||
|  |     public int $per_page = 10; | ||||||
| 
 | 
 | ||||||
|     public string $tab = 'documents'; |     public string $tab = 'documents'; | ||||||
| 
 | 
 | ||||||
|  |     public string $db; | ||||||
|  | 
 | ||||||
|     protected $query; |     protected $query; | ||||||
| 
 | 
 | ||||||
|     public function mount($client) |     public function mount() | ||||||
|     { |     { | ||||||
|         MultiDB::setDb($this->company->db); |         MultiDB::setDb($this->db); | ||||||
| 
 | 
 | ||||||
|         $this->client = $client; |         $this->client = Client::with('company')->find($this->client_id); | ||||||
|  | 
 | ||||||
|  |         $this->company = $this->client->company; | ||||||
| 
 | 
 | ||||||
|         $this->query = $this->documents(); |         $this->query = $this->documents(); | ||||||
|     } |     } | ||||||
|  | |||||||
| @ -13,6 +13,7 @@ | |||||||
| namespace App\Http\Livewire; | namespace App\Http\Livewire; | ||||||
| 
 | 
 | ||||||
| use App\Libraries\MultiDB; | use App\Libraries\MultiDB; | ||||||
|  | use App\Models\Company; | ||||||
| use App\Models\Invoice; | use App\Models\Invoice; | ||||||
| use App\Utils\Traits\WithSorting; | use App\Utils\Traits\WithSorting; | ||||||
| use Carbon\Carbon; | use Carbon\Carbon; | ||||||
| @ -23,15 +24,21 @@ class InvoicesTable extends Component | |||||||
| { | { | ||||||
|     use WithPagination, WithSorting; |     use WithPagination, WithSorting; | ||||||
| 
 | 
 | ||||||
|     public $per_page = 10; |     public int $per_page = 10; | ||||||
| 
 | 
 | ||||||
|     public $status = []; |     public array $status = []; | ||||||
| 
 | 
 | ||||||
|     public $company; |     public Company $company; | ||||||
|  | 
 | ||||||
|  |     public int $company_id; | ||||||
|  | 
 | ||||||
|  |     public string $db; | ||||||
| 
 | 
 | ||||||
|     public function mount() |     public function mount() | ||||||
|     { |     { | ||||||
|         MultiDB::setDb($this->company->db); |         MultiDB::setDb($this->db); | ||||||
|  | 
 | ||||||
|  |         $this->company = Company::find($this->company_id); | ||||||
| 
 | 
 | ||||||
|         $this->sort_asc = false; |         $this->sort_asc = false; | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -23,13 +23,11 @@ class PayNowDropdown extends Component | |||||||
| 
 | 
 | ||||||
|     public $company; |     public $company; | ||||||
| 
 | 
 | ||||||
|     public function mount(int $total) |     public function mount() | ||||||
|     { |     { | ||||||
|         MultiDB::setDb($this->company->db); |         MultiDB::setDb($this->company->db); | ||||||
| 
 | 
 | ||||||
|         $this->total = $total; |         $this->methods = auth()->guard('contact')->user()->client->service()->getPaymentMethods($this->total); | ||||||
| 
 |  | ||||||
|         $this->methods = auth()->guard('contact')->user()->client->service()->getPaymentMethods($total); |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     public function render() |     public function render() | ||||||
|  | |||||||
| @ -3,7 +3,9 @@ | |||||||
| namespace App\Http\Livewire; | namespace App\Http\Livewire; | ||||||
| 
 | 
 | ||||||
| use App\Libraries\MultiDB; | use App\Libraries\MultiDB; | ||||||
|  | use App\Models\Client; | ||||||
| use App\Models\ClientGatewayToken; | use App\Models\ClientGatewayToken; | ||||||
|  | use App\Models\Company; | ||||||
| use App\Utils\Traits\WithSorting; | use App\Utils\Traits\WithSorting; | ||||||
| use Livewire\Component; | use Livewire\Component; | ||||||
| use Livewire\WithPagination; | use Livewire\WithPagination; | ||||||
| @ -13,17 +15,23 @@ class PaymentMethodsTable extends Component | |||||||
|     use WithPagination; |     use WithPagination; | ||||||
|     use WithSorting; |     use WithSorting; | ||||||
| 
 | 
 | ||||||
|     public $per_page = 10; |     public int $per_page = 10; | ||||||
| 
 | 
 | ||||||
|     public $client; |     public Client $client; | ||||||
| 
 | 
 | ||||||
|     public $company; |     public Company $company; | ||||||
| 
 | 
 | ||||||
|     public function mount($client) |     public int $client_id; | ||||||
|  | 
 | ||||||
|  |     public string $db; | ||||||
|  | 
 | ||||||
|  |     public function mount() | ||||||
|     { |     { | ||||||
|         MultiDB::setDb($this->company->db); |         MultiDB::setDb($this->db); | ||||||
| 
 | 
 | ||||||
|         $this->client = $client; |         $this->client = Client::with('company')->find($this->client_id); | ||||||
|  | 
 | ||||||
|  |         $this->company = $this->client->company; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     public function render() |     public function render() | ||||||
|  | |||||||
| @ -13,6 +13,7 @@ | |||||||
| namespace App\Http\Livewire; | namespace App\Http\Livewire; | ||||||
| 
 | 
 | ||||||
| use App\Libraries\MultiDB; | use App\Libraries\MultiDB; | ||||||
|  | use App\Models\Company; | ||||||
| use App\Models\Payment; | use App\Models\Payment; | ||||||
| use App\Utils\Traits\WithSorting; | use App\Utils\Traits\WithSorting; | ||||||
| use Livewire\Component; | use Livewire\Component; | ||||||
| @ -23,17 +24,19 @@ class PaymentsTable extends Component | |||||||
|     use WithSorting; |     use WithSorting; | ||||||
|     use WithPagination; |     use WithPagination; | ||||||
| 
 | 
 | ||||||
|     public $per_page = 10; |     public int $per_page = 10; | ||||||
| 
 | 
 | ||||||
|     public $user; |     public Company $company; | ||||||
| 
 | 
 | ||||||
|     public $company; |     public int $company_id; | ||||||
|  | 
 | ||||||
|  |     public string $db; | ||||||
| 
 | 
 | ||||||
|     public function mount() |     public function mount() | ||||||
|     { |     { | ||||||
|         MultiDB::setDb($this->company->db); |         MultiDB::setDb($this->db); | ||||||
| 
 | 
 | ||||||
|         $this->user = auth()->user(); |         $this->company = Company::find($this->company_id); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     public function render() |     public function render() | ||||||
| @ -43,7 +46,7 @@ class PaymentsTable extends Component | |||||||
|             ->where('company_id', $this->company->id) |             ->where('company_id', $this->company->id) | ||||||
|             ->where('client_id', auth()->guard('contact')->user()->client_id) |             ->where('client_id', auth()->guard('contact')->user()->client_id) | ||||||
|             ->whereIn('status_id', [Payment::STATUS_FAILED, Payment::STATUS_COMPLETED, Payment::STATUS_PENDING, Payment::STATUS_REFUNDED, Payment::STATUS_PARTIALLY_REFUNDED]) |             ->whereIn('status_id', [Payment::STATUS_FAILED, Payment::STATUS_COMPLETED, Payment::STATUS_PENDING, Payment::STATUS_REFUNDED, Payment::STATUS_PARTIALLY_REFUNDED]) | ||||||
|             ->orderBy($this->sort_field, $this->sort_asc ? 'asc' : 'desc') |             ->orderBy($this->sort_field, $this->sort_asc ? 'desc' : 'asc') | ||||||
|             ->withTrashed() |             ->withTrashed() | ||||||
|             ->paginate($this->per_page); |             ->paginate($this->per_page); | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -13,6 +13,7 @@ | |||||||
| namespace App\Http\Livewire; | namespace App\Http\Livewire; | ||||||
| 
 | 
 | ||||||
| use App\Libraries\MultiDB; | use App\Libraries\MultiDB; | ||||||
|  | use App\Models\Company; | ||||||
| use App\Models\Quote; | use App\Models\Quote; | ||||||
| use App\Utils\Traits\WithSorting; | use App\Utils\Traits\WithSorting; | ||||||
| use Livewire\Component; | use Livewire\Component; | ||||||
| @ -22,15 +23,27 @@ class QuotesTable extends Component | |||||||
| { | { | ||||||
|     use WithPagination; |     use WithPagination; | ||||||
| 
 | 
 | ||||||
|     public $per_page = 10; |     public int $per_page = 10; | ||||||
| 
 | 
 | ||||||
|     public $status = []; |     public array $status = []; | ||||||
| 
 | 
 | ||||||
|     public $company; |     public Company $company; | ||||||
| 
 | 
 | ||||||
|     public $sort = 'status_id'; // Default sortBy. Feel free to change or pull from client/company settings.
 |     public string $sort = 'status_id';  | ||||||
|  | 
 | ||||||
|  |     public bool $sort_asc = true; | ||||||
|  | 
 | ||||||
|  |     public int $company_id; | ||||||
|  | 
 | ||||||
|  |     public string $db; | ||||||
|  | 
 | ||||||
|  |     public function mount() | ||||||
|  |     { | ||||||
|  |         MultiDB::setDb($this->db); | ||||||
|  | 
 | ||||||
|  |         $this->company = Company::find($this->company_id); | ||||||
|  |     } | ||||||
| 
 | 
 | ||||||
|     public $sort_asc = true; |  | ||||||
| 
 | 
 | ||||||
|     public function sortBy($field) |     public function sortBy($field) | ||||||
|     { |     { | ||||||
| @ -41,16 +54,11 @@ class QuotesTable extends Component | |||||||
|         $this->sort = $field; |         $this->sort = $field; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     public function mount() |  | ||||||
|     { |  | ||||||
|         MultiDB::setDb($this->company->db); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     public function render() |     public function render() | ||||||
|     { |     { | ||||||
| 
 | 
 | ||||||
|         $query = Quote::query() |         $query = Quote::query() | ||||||
|             ->with('client.gateway_tokens', 'company', 'client.contacts') |             ->with('client.contacts', 'company') | ||||||
|             ->orderBy($this->sort, $this->sort_asc ? 'asc' : 'desc'); |             ->orderBy($this->sort, $this->sort_asc ? 'asc' : 'desc'); | ||||||
| 
 | 
 | ||||||
|         if (count($this->status) > 0) { |         if (count($this->status) > 0) { | ||||||
|  | |||||||
| @ -142,7 +142,7 @@ class SubscriptionPlanSwitch extends Component | |||||||
|     { |     { | ||||||
|         $this->hide_button = true; |         $this->hide_button = true; | ||||||
| 
 | 
 | ||||||
|         $response =  $this->target->service()->createChangePlanCredit([ |         $response =  $this->target->service()->createChangePlanCreditV2([ | ||||||
|             'recurring_invoice' => $this->recurring_invoice, |             'recurring_invoice' => $this->recurring_invoice, | ||||||
|             'subscription' => $this->subscription, |             'subscription' => $this->subscription, | ||||||
|             'target' => $this->target, |             'target' => $this->target, | ||||||
|  | |||||||
							
								
								
									
										51
									
								
								app/Http/Livewire/SubscriptionsTable.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										51
									
								
								app/Http/Livewire/SubscriptionsTable.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,51 @@ | |||||||
|  | <?php | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Invoice Ninja (https://invoiceninja.com). | ||||||
|  |  * | ||||||
|  |  * @link https://github.com/invoiceninja/invoiceninja source repository | ||||||
|  |  * | ||||||
|  |  * @copyright Copyright (c) 2022. Invoice Ninja LLC (https://invoiceninja.com) | ||||||
|  |  * | ||||||
|  |  * @license https://www.elastic.co/licensing/elastic-license | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | namespace App\Http\Livewire; | ||||||
|  | 
 | ||||||
|  | use App\Libraries\MultiDB; | ||||||
|  | use App\Models\RecurringInvoice; | ||||||
|  | use App\Utils\Traits\WithSorting; | ||||||
|  | use Livewire\Component; | ||||||
|  | use Livewire\WithPagination; | ||||||
|  | 
 | ||||||
|  | class SubscriptionsTable extends Component | ||||||
|  | { | ||||||
|  |     use WithPagination; | ||||||
|  |     use WithSorting; | ||||||
|  | 
 | ||||||
|  |     public $per_page = 10; | ||||||
|  | 
 | ||||||
|  |     public $company; | ||||||
|  | 
 | ||||||
|  |     public function mount() | ||||||
|  |     { | ||||||
|  |         MultiDB::setDb($this->company->db); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public function render() | ||||||
|  |     { | ||||||
|  |         $query = RecurringInvoice::query() | ||||||
|  |             ->where('client_id', auth()->guard('contact')->user()->client->id) | ||||||
|  |             ->where('company_id', $this->company->id) | ||||||
|  |             ->whereNotNull('subscription_id') | ||||||
|  |             ->where('is_deleted', false) | ||||||
|  |             ->where('status_id', RecurringInvoice::STATUS_ACTIVE) | ||||||
|  |             ->orderBy($this->sort_field, $this->sort_asc ? 'asc' : 'desc') | ||||||
|  |             ->withTrashed() | ||||||
|  |             ->paginate($this->per_page); | ||||||
|  | 
 | ||||||
|  |         return render('components.livewire.subscriptions-table', [ | ||||||
|  |             'recurring_invoices' => $query, | ||||||
|  |         ]); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -18,6 +18,7 @@ use Illuminate\Http\Request; | |||||||
| use Illuminate\Support\Facades\Cache; | use Illuminate\Support\Facades\Cache; | ||||||
| use Illuminate\Support\Facades\Hash; | use Illuminate\Support\Facades\Hash; | ||||||
| use Illuminate\Support\Str; | use Illuminate\Support\Str; | ||||||
|  | use Laravel\Socialite\Facades\Socialite; | ||||||
| use stdClass; | use stdClass; | ||||||
| 
 | 
 | ||||||
| class PasswordProtection | class PasswordProtection | ||||||
| @ -111,7 +112,18 @@ class PasswordProtection | |||||||
|                     return $next($request); |                     return $next($request); | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|  |             elseif(auth()->user()->oauth_provider_id == 'apple') | ||||||
|  |             { | ||||||
|                  |                  | ||||||
|  |                 $user = Socialite::driver('apple')->userFromToken($request->header('X-API-OAUTH-PASSWORD')); | ||||||
|  | 
 | ||||||
|  |                 if($user && ($user->email == auth()->user()->email)){ | ||||||
|  | 
 | ||||||
|  |                     Cache::put(auth()->user()->hashed_id.'_'.auth()->user()->account_id.'_logged_in', Str::random(64), $timeout); | ||||||
|  |                     return $next($request); | ||||||
|  |                 } | ||||||
|  |                  | ||||||
|  |             } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|             return response()->json($error, 412); |             return response()->json($error, 412); | ||||||
|  | |||||||
| @ -64,21 +64,22 @@ class MatchBankTransactionRequest extends Request | |||||||
| 
 | 
 | ||||||
|             if(array_key_exists('payment_id', $inputs['transactions'][$key]) && strlen($inputs['transactions'][$key]['payment_id']) >= 1){ |             if(array_key_exists('payment_id', $inputs['transactions'][$key]) && strlen($inputs['transactions'][$key]['payment_id']) >= 1){ | ||||||
|                 $inputs['transactions'][$key]['payment_id'] = $this->decodePrimaryKey($inputs['transactions'][$key]['payment_id']); |                 $inputs['transactions'][$key]['payment_id'] = $this->decodePrimaryKey($inputs['transactions'][$key]['payment_id']); | ||||||
|                 $p = Payment::withTrashed()->find($inputs['transactions'][$key]['payment_id']); |                 $p = Payment::withTrashed()->where('company_id', auth()->user()->company()->id)->where('id', $inputs['transactions'][$key]['payment_id'])->first(); | ||||||
| 
 | 
 | ||||||
|                 /*Ensure we don't relink an existing payment*/ |                 /*Ensure we don't relink an existing payment*/ | ||||||
|                 if(!$p || $p->transaction_id) |                 if(!$p || is_numeric($p->transaction_id)){ | ||||||
|                     $inputs['transactions'][$key]['payment_id'] = null; |                     unset($inputs['transactions'][$key]); | ||||||
|  |                 } | ||||||
| 
 | 
 | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             if(array_key_exists('expense_id', $inputs['transactions'][$key]) && strlen($inputs['transactions'][$key]['expense_id']) >= 1){ |             if(array_key_exists('expense_id', $inputs['transactions'][$key]) && strlen($inputs['transactions'][$key]['expense_id']) >= 1){ | ||||||
|                 $inputs['transactions'][$key]['expense_id'] = $this->decodePrimaryKey($inputs['transactions'][$key]['expense_id']); |                 $inputs['transactions'][$key]['expense_id'] = $this->decodePrimaryKey($inputs['transactions'][$key]['expense_id']); | ||||||
|                 $e = Expense::withTrashed()->find($inputs['transactions'][$key]['expense_id']); |                 $e = Expense::withTrashed()->where('company_id', auth()->user()->company()->id)->where('id', $inputs['transactions'][$key]['expense_id'])->first(); | ||||||
| 
 | 
 | ||||||
|                 /*Ensure we don't relink an existing expense*/ |                 /*Ensure we don't relink an existing expense*/ | ||||||
|                 if(!$e || $e->transaction_id) |                 if(!$e || is_numeric($e->transaction_id)) | ||||||
|                     $inputs['transactions'][$key]['expense_id'] = null; |                     unset($inputs['transactions'][$key]['expense_id']); | ||||||
| 
 | 
 | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -47,7 +47,7 @@ class RegisterRequest extends FormRequest | |||||||
| 
 | 
 | ||||||
|         foreach ($rules as $field => $properties) { |         foreach ($rules as $field => $properties) { | ||||||
|             if ($field === 'email') { |             if ($field === 'email') { | ||||||
|                 $rules[$field] = array_merge($rules[$field], ['email:rfc,dns', 'max:255', Rule::unique('client_contacts')->where('company_id', $this->company()->id)]); |                 $rules[$field] = array_merge($rules[$field], ['email:rfc,dns', 'max:191', Rule::unique('client_contacts')->where('company_id', $this->company()->id)]); | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             if ($field === 'current_password') { |             if ($field === 'current_password') { | ||||||
|  | |||||||
| @ -40,8 +40,6 @@ class UpdateCompanyRequest extends Request | |||||||
|         return auth()->user()->can('edit', $this->company); |         return auth()->user()->can('edit', $this->company); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
|     public function rules() |     public function rules() | ||||||
|     { |     { | ||||||
|         $input = $this->all(); |         $input = $this->all(); | ||||||
| @ -110,7 +108,8 @@ class UpdateCompanyRequest extends Request | |||||||
|             } |             } | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         $settings['email_style_custom'] = str_replace(['{{','}}'], ['',''], $settings['email_style_custom']); |         if(isset($settings['email_style_custom'])) | ||||||
|  |             $settings['email_style_custom'] = str_replace(['{{','}}'], ['',''], $settings['email_style_custom']); | ||||||
| 
 | 
 | ||||||
|         if (! $account->isFreeHostedClient()) { |         if (! $account->isFreeHostedClient()) { | ||||||
|             return $settings; |             return $settings; | ||||||
|  | |||||||
| @ -41,7 +41,7 @@ class StoreExpenseRequest extends Request | |||||||
|             $rules['number'] = Rule::unique('expenses')->where('company_id', auth()->user()->company()->id); |             $rules['number'] = Rule::unique('expenses')->where('company_id', auth()->user()->company()->id); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         if (! empty($this->client_id)) { |         if ($this->client_id) { | ||||||
|             $rules['client_id'] = 'bail|sometimes|exists:clients,id,company_id,'.auth()->user()->company()->id; |             $rules['client_id'] = 'bail|sometimes|exists:clients,id,company_id,'.auth()->user()->company()->id; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -41,6 +41,10 @@ class UpdateExpenseRequest extends Request | |||||||
|             $rules['number'] = Rule::unique('expenses')->where('company_id', auth()->user()->company()->id)->ignore($this->expense->id); |             $rules['number'] = Rule::unique('expenses')->where('company_id', auth()->user()->company()->id)->ignore($this->expense->id); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  |         if ($this->client_id) { | ||||||
|  |             $rules['client_id'] = 'bail|sometimes|exists:clients,id,company_id,'.auth()->user()->company()->id; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|         $rules['category_id'] = 'bail|sometimes|nullable|exists:expense_categories,id,company_id,'.auth()->user()->company()->id.',is_deleted,0'; |         $rules['category_id'] = 'bail|sometimes|nullable|exists:expense_categories,id,company_id,'.auth()->user()->company()->id.',is_deleted,0'; | ||||||
| 
 | 
 | ||||||
|         return $this->globalRules($rules); |         return $this->globalRules($rules); | ||||||
|  | |||||||
| @ -47,7 +47,8 @@ class PaymentWebhookRequest extends Request | |||||||
|     { |     { | ||||||
|         MultiDB::findAndSetDbByCompanyKey($this->company_key); |         MultiDB::findAndSetDbByCompanyKey($this->company_key); | ||||||
| 
 | 
 | ||||||
|         return CompanyGateway::withTrashed()->findOrFail($this->decodePrimaryKey($this->company_gateway_id)); |         return CompanyGateway::withTrashed()->find($this->decodePrimaryKey($this->company_gateway_id)); | ||||||
|  | 
 | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /** |     /** | ||||||
|  | |||||||
| @ -43,6 +43,7 @@ class StoreRecurringExpenseRequest extends Request | |||||||
|             $rules['client_id'] = 'bail|sometimes|exists:clients,id,company_id,'.auth()->user()->company()->id; |             $rules['client_id'] = 'bail|sometimes|exists:clients,id,company_id,'.auth()->user()->company()->id; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  |         $rules['category_id'] = 'bail|nullable|sometimes|exists:expense_categories,id,company_id,'.auth()->user()->company()->id.',is_deleted,0'; | ||||||
|         $rules['frequency_id'] = 'required|integer|digits_between:1,12'; |         $rules['frequency_id'] = 'required|integer|digits_between:1,12'; | ||||||
|         $rules['tax_amount1'] = 'numeric'; |         $rules['tax_amount1'] = 'numeric'; | ||||||
|         $rules['tax_amount2'] = 'numeric'; |         $rules['tax_amount2'] = 'numeric'; | ||||||
| @ -61,10 +62,6 @@ class StoreRecurringExpenseRequest extends Request | |||||||
|             $input['next_send_date_client'] = $input['next_send_date']; |             $input['next_send_date_client'] = $input['next_send_date']; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         if (array_key_exists('category_id', $input) && is_string($input['category_id'])) { |  | ||||||
|             $input['category_id'] = $this->decodePrimaryKey($input['category_id']); |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         if (! array_key_exists('currency_id', $input) || strlen($input['currency_id']) == 0) { |         if (! array_key_exists('currency_id', $input) || strlen($input['currency_id']) == 0) { | ||||||
|             $input['currency_id'] = (string) auth()->user()->company()->settings->currency_id; |             $input['currency_id'] = (string) auth()->user()->company()->settings->currency_id; | ||||||
|         } |         } | ||||||
|  | |||||||
| @ -46,6 +46,7 @@ class UpdateRecurringExpenseRequest extends Request | |||||||
|         $rules['tax_amount1'] = 'numeric'; |         $rules['tax_amount1'] = 'numeric'; | ||||||
|         $rules['tax_amount2'] = 'numeric'; |         $rules['tax_amount2'] = 'numeric'; | ||||||
|         $rules['tax_amount3'] = 'numeric'; |         $rules['tax_amount3'] = 'numeric'; | ||||||
|  |         $rules['category_id'] = 'bail|nullable|sometimes|exists:expense_categories,id,company_id,'.auth()->user()->company()->id.',is_deleted,0'; | ||||||
| 
 | 
 | ||||||
|         return $this->globalRules($rules); |         return $this->globalRules($rules); | ||||||
|     } |     } | ||||||
| @ -70,10 +71,6 @@ class UpdateRecurringExpenseRequest extends Request | |||||||
|             $input['next_send_date_client'] = $input['next_send_date']; |             $input['next_send_date_client'] = $input['next_send_date']; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         if (array_key_exists('category_id', $input) && is_string($input['category_id'])) { |  | ||||||
|             $input['category_id'] = $this->decodePrimaryKey($input['category_id']); |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         if (array_key_exists('documents', $input)) { |         if (array_key_exists('documents', $input)) { | ||||||
|             unset($input['documents']); |             unset($input['documents']); | ||||||
|         } |         } | ||||||
|  | |||||||
							
								
								
									
										71
									
								
								app/Http/Requests/Report/ProductSalesReportRequest.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										71
									
								
								app/Http/Requests/Report/ProductSalesReportRequest.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,71 @@ | |||||||
|  | <?php | ||||||
|  | /** | ||||||
|  |  * Invoice Ninja (https://invoiceninja.com). | ||||||
|  |  * | ||||||
|  |  * @link https://github.com/invoiceninja/invoiceninja source repository | ||||||
|  |  * | ||||||
|  |  * @copyright Copyright (c) 2022. Invoice Ninja LLC (https://invoiceninja.com) | ||||||
|  |  * | ||||||
|  |  * @license https://www.elastic.co/licensing/elastic-license | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | namespace App\Http\Requests\Report; | ||||||
|  | 
 | ||||||
|  | use App\Http\Requests\Request; | ||||||
|  | use App\Utils\Traits\MakesHash; | ||||||
|  | use Illuminate\Validation\Rule; | ||||||
|  | 
 | ||||||
|  | class ProductSalesReportRequest extends Request | ||||||
|  | { | ||||||
|  |     use MakesHash; | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * Determine if the user is authorized to make this request. | ||||||
|  |      * | ||||||
|  |      * @return bool | ||||||
|  |      */ | ||||||
|  |     public function authorize() : bool | ||||||
|  |     { | ||||||
|  |         return auth()->user()->isAdmin(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public function rules() | ||||||
|  |     { | ||||||
|  | 
 | ||||||
|  |         return [ | ||||||
|  |             'date_range' => 'bail|required|string', | ||||||
|  |             'end_date' => 'bail|required_if:date_range,custom|nullable|date', | ||||||
|  |             'start_date' => 'bail|required_if:date_range,custom|nullable|date', | ||||||
|  |             'report_keys' => 'bail|present|array', | ||||||
|  |             'send_email' => 'bail|required|bool', | ||||||
|  |             'client_id' => 'bail|sometimes|exists:clients,id,company_id,'.auth()->user()->company()->id.',is_deleted,0', | ||||||
|  |         ]; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public function prepareForValidation() | ||||||
|  |     { | ||||||
|  |         $input = $this->all(); | ||||||
|  | 
 | ||||||
|  |         if (! array_key_exists('date_range', $input)) { | ||||||
|  |             $input['date_range'] = 'all'; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         if (! array_key_exists('report_keys', $input)) { | ||||||
|  |             $input['report_keys'] = []; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         if (! array_key_exists('send_email', $input)) { | ||||||
|  |             $input['send_email'] = true; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         if (array_key_exists('date_range', $input) && $input['date_range'] != 'custom') { | ||||||
|  |             $input['start_date'] = null; | ||||||
|  |             $input['end_date'] = null; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         if(array_key_exists('client_id', $input) && strlen($input['client_id']) >=1) | ||||||
|  |             $input['client_id'] = $this->decodePrimaryKey($input['client_id']); | ||||||
|  | 
 | ||||||
|  |         $this->replace($input); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -32,8 +32,6 @@ class CheckMailRequest extends Request | |||||||
|      */ |      */ | ||||||
|     public function rules() |     public function rules() | ||||||
|     { |     { | ||||||
|         nlog($this->driver); |  | ||||||
| 
 |  | ||||||
|         return [ |         return [ | ||||||
|             'mail_driver' => 'required', |             'mail_driver' => 'required', | ||||||
|             'encryption' => 'required_unless:mail_driver,log', |             'encryption' => 'required_unless:mail_driver,log', | ||||||
|  | |||||||
| @ -1,39 +0,0 @@ | |||||||
| <?php |  | ||||||
| 
 |  | ||||||
| namespace App\Http\Requests\TaskScheduler; |  | ||||||
| 
 |  | ||||||
| use App\Http\Requests\Request; |  | ||||||
| 
 |  | ||||||
| class CreateScheduledTaskRequest extends Request |  | ||||||
| { |  | ||||||
|     /** |  | ||||||
|      * Determine if the user is authorized to make this request. |  | ||||||
|      * |  | ||||||
|      * @return bool |  | ||||||
|      */ |  | ||||||
|     public function authorize(): bool |  | ||||||
|     { |  | ||||||
|         return auth()->user()->isAdmin(); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     public function rules() |  | ||||||
|     { |  | ||||||
|         return [ |  | ||||||
|             'paused' => 'sometimes|bool', |  | ||||||
|             'repeat_every' => 'required|string|in:DAY,WEEK,MONTH,3MONTHS,YEAR', |  | ||||||
|             'start_from' => 'sometimes|string', |  | ||||||
|             'job' => 'required', |  | ||||||
|         ]; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     public function prepareForValidation() |  | ||||||
|     { |  | ||||||
|         $input = $this->all(); |  | ||||||
| 
 |  | ||||||
|         if (! array_key_exists('start_from', $input)) { |  | ||||||
|             $input['start_from'] = now(); |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         $this->replace($input); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
							
								
								
									
										28
									
								
								app/Http/Requests/TaskScheduler/CreateSchedulerRequest.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								app/Http/Requests/TaskScheduler/CreateSchedulerRequest.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,28 @@ | |||||||
|  | <?php | ||||||
|  | /** | ||||||
|  |  * Invoice Ninja (https://invoiceninja.com). | ||||||
|  |  * | ||||||
|  |  * @link https://github.com/invoiceninja/invoiceninja source repository | ||||||
|  |  * | ||||||
|  |  * @copyright Copyright (c) 2022. Invoice Ninja LLC (https://invoiceninja.com) | ||||||
|  |  * | ||||||
|  |  * @license https://www.elastic.co/licensing/elastic-license | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | namespace App\Http\Requests\TaskScheduler; | ||||||
|  | 
 | ||||||
|  | use App\Http\Requests\Request; | ||||||
|  | 
 | ||||||
|  | class CreateSchedulerRequest extends Request | ||||||
|  | { | ||||||
|  |     /** | ||||||
|  |      * Determine if the user is authorized to make this request. | ||||||
|  |      * | ||||||
|  |      * @return bool | ||||||
|  |      */ | ||||||
|  |     public function authorize(): bool | ||||||
|  |     { | ||||||
|  |         return auth()->user()->isAdmin(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  | } | ||||||
							
								
								
									
										27
									
								
								app/Http/Requests/TaskScheduler/DestroySchedulerRequest.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								app/Http/Requests/TaskScheduler/DestroySchedulerRequest.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,27 @@ | |||||||
|  | <?php | ||||||
|  | /** | ||||||
|  |  * Invoice Ninja (https://invoiceninja.com). | ||||||
|  |  * | ||||||
|  |  * @link https://github.com/invoiceninja/invoiceninja source repository | ||||||
|  |  * | ||||||
|  |  * @copyright Copyright (c) 2022. Invoice Ninja LLC (https://invoiceninja.com) | ||||||
|  |  * | ||||||
|  |  * @license https://www.elastic.co/licensing/elastic-license | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | namespace App\Http\Requests\Task; | ||||||
|  | 
 | ||||||
|  | use App\Http\Requests\Request; | ||||||
|  | 
 | ||||||
|  | class DestroySchedulerRequest extends Request | ||||||
|  | { | ||||||
|  |     /** | ||||||
|  |      * Determine if the user is authorized to make this request. | ||||||
|  |      * | ||||||
|  |      * @return bool | ||||||
|  |      */ | ||||||
|  |     public function authorize() : bool | ||||||
|  |     { | ||||||
|  |         return auth()->user()->isAdmin(); | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										27
									
								
								app/Http/Requests/TaskScheduler/ShowSchedulerRequest.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								app/Http/Requests/TaskScheduler/ShowSchedulerRequest.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,27 @@ | |||||||
|  | <?php | ||||||
|  | /** | ||||||
|  |  * Invoice Ninja (https://invoiceninja.com). | ||||||
|  |  * | ||||||
|  |  * @link https://github.com/invoiceninja/invoiceninja source repository | ||||||
|  |  * | ||||||
|  |  * @copyright Copyright (c) 2022. Invoice Ninja LLC (https://invoiceninja.com) | ||||||
|  |  * | ||||||
|  |  * @license https://www.elastic.co/licensing/elastic-license | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | namespace App\Http\Requests\TaskScheduler; | ||||||
|  | 
 | ||||||
|  | use App\Http\Requests\Request; | ||||||
|  | 
 | ||||||
|  | class ShowSchedulerRequest extends Request | ||||||
|  | { | ||||||
|  |     /** | ||||||
|  |      * Determine if the user is authorized to make this request. | ||||||
|  |      * | ||||||
|  |      * @return bool | ||||||
|  |      */ | ||||||
|  |     public function authorize() : bool | ||||||
|  |     { | ||||||
|  |         return auth()->user()->can('view', $this->scheduler); | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										44
									
								
								app/Http/Requests/TaskScheduler/StoreSchedulerRequest.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										44
									
								
								app/Http/Requests/TaskScheduler/StoreSchedulerRequest.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,44 @@ | |||||||
|  | <?php | ||||||
|  | /** | ||||||
|  |  * Invoice Ninja (https://invoiceninja.com). | ||||||
|  |  * | ||||||
|  |  * @link https://github.com/invoiceninja/invoiceninja source repository | ||||||
|  |  * | ||||||
|  |  * @copyright Copyright (c) 2022. Invoice Ninja LLC (https://invoiceninja.com) | ||||||
|  |  * | ||||||
|  |  * @license https://www.elastic.co/licensing/elastic-license | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | namespace App\Http\Requests\TaskScheduler; | ||||||
|  | 
 | ||||||
|  | use App\Http\Requests\Request; | ||||||
|  | use Illuminate\Validation\Rule; | ||||||
|  | 
 | ||||||
|  | class StoreSchedulerRequest extends Request | ||||||
|  | { | ||||||
|  |     /** | ||||||
|  |      * Determine if the user is authorized to make this request. | ||||||
|  |      * | ||||||
|  |      * @return bool | ||||||
|  |      */ | ||||||
|  |     public function authorize(): bool | ||||||
|  |     { | ||||||
|  |         return auth()->user()->isAdmin(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public function rules() | ||||||
|  |     { | ||||||
|  | 
 | ||||||
|  |         $rules = [ | ||||||
|  |             'name' => ['bail', 'required', Rule::unique('schedulers')->where('company_id', auth()->user()->company()->id)], | ||||||
|  |             'is_paused' => 'bail|sometimes|boolean', | ||||||
|  |             'frequency_id' => 'bail|required|integer|digits_between:1,12', | ||||||
|  |             'next_run' => 'bail|required|date:Y-m-d', | ||||||
|  |             'template' => 'bail|required|string', | ||||||
|  |             'parameters' => 'bail|array', | ||||||
|  |         ]; | ||||||
|  | 
 | ||||||
|  |         return $rules; | ||||||
|  | 
 | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -1,25 +0,0 @@ | |||||||
| <?php |  | ||||||
| 
 |  | ||||||
| namespace App\Http\Requests\TaskScheduler; |  | ||||||
| 
 |  | ||||||
| use App\Http\Requests\Request; |  | ||||||
| 
 |  | ||||||
| class UpdateScheduledJobRequest extends Request |  | ||||||
| { |  | ||||||
|     /** |  | ||||||
|      * Determine if the user is authorized to make this request. |  | ||||||
|      * |  | ||||||
|      * @return bool |  | ||||||
|      */ |  | ||||||
|     public function authorize(): bool |  | ||||||
|     { |  | ||||||
|         return auth()->user()->isAdmin(); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     public function rules(): array |  | ||||||
|     { |  | ||||||
|         return [ |  | ||||||
|             'action_name' => 'sometimes|string', |  | ||||||
|         ]; |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @ -8,14 +8,12 @@ | |||||||
|  * |  * | ||||||
|  * @license https://www.elastic.co/licensing/elastic-license |  * @license https://www.elastic.co/licensing/elastic-license | ||||||
|  */ |  */ | ||||||
| 
 |  | ||||||
| namespace App\Http\Requests\TaskScheduler; | namespace App\Http\Requests\TaskScheduler; | ||||||
| 
 | 
 | ||||||
| use App\Http\Requests\Request; | use App\Http\Requests\Request; | ||||||
| use Carbon\Carbon; |  | ||||||
| use Illuminate\Validation\Rule; | use Illuminate\Validation\Rule; | ||||||
| 
 | 
 | ||||||
| class UpdateScheduleRequest extends Request | class UpdateSchedulerRequest extends Request | ||||||
| { | { | ||||||
|     /** |     /** | ||||||
|      * Determine if the user is authorized to make this request. |      * Determine if the user is authorized to make this request. | ||||||
| @ -29,23 +27,17 @@ class UpdateScheduleRequest extends Request | |||||||
| 
 | 
 | ||||||
|     public function rules(): array |     public function rules(): array | ||||||
|     { |     { | ||||||
|         return [ | 
 | ||||||
|             'paused' => 'sometimes|bool', |         $rules = [ | ||||||
|             'repeat_every' => 'sometimes|string|in:DAY,WEEK,BIWEEKLY,MONTH,3MONTHS,YEAR', |             'name' => ['bail', 'sometimes', Rule::unique('schedulers')->where('company_id', auth()->user()->company()->id)->ignore($this->task_scheduler->id)], | ||||||
|             'start_from' => 'sometimes', |             'is_paused' => 'bail|sometimes|boolean', | ||||||
|             'scheduled_run'=>'sometimes', |             'frequency_id' => 'bail|required|integer|digits_between:1,12', | ||||||
|  |             'next_run' => 'bail|required|date:Y-m-d', | ||||||
|  |             'template' => 'bail|required|string', | ||||||
|  |             'parameters' => 'bail|array', | ||||||
|         ]; |         ]; | ||||||
|     } |  | ||||||
| 
 | 
 | ||||||
|     public function prepareForValidation() |         return $rules; | ||||||
|     { |  | ||||||
|         $input = $this->all(); |  | ||||||
|          |          | ||||||
|         if (isset($input['start_from'])) { |  | ||||||
|             $input['scheduled_run'] = Carbon::parse((int) $input['start_from']); |  | ||||||
|             $input['start_from'] = Carbon::parse((int) $input['start_from']); |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         $this->replace($input); |  | ||||||
|     } |     } | ||||||
| } | } | ||||||
| @ -29,6 +29,7 @@ class BlackListRule implements Rule | |||||||
|         'dataservices.space', |         'dataservices.space', | ||||||
|         'karenkey.com', |         'karenkey.com', | ||||||
|         'sharklasers.com', |         'sharklasers.com', | ||||||
|  |         '100072641.help' | ||||||
|     ]; |     ]; | ||||||
| 
 | 
 | ||||||
|     /** |     /** | ||||||
|  | |||||||
| @ -20,7 +20,7 @@ use App\Http\Requests\Quote\StoreQuoteRequest; | |||||||
| use App\Import\ImportException; | use App\Import\ImportException; | ||||||
| use App\Jobs\Mail\NinjaMailerJob; | use App\Jobs\Mail\NinjaMailerJob; | ||||||
| use App\Jobs\Mail\NinjaMailerObject; | use App\Jobs\Mail\NinjaMailerObject; | ||||||
| use App\Mail\Import\ImportCompleted; | use App\Mail\Import\CsvImportCompleted; | ||||||
| use App\Models\Company; | use App\Models\Company; | ||||||
| use App\Models\Invoice; | use App\Models\Invoice; | ||||||
| use App\Models\Quote; | use App\Models\Quote; | ||||||
| @ -187,6 +187,10 @@ class BaseImport | |||||||
| 
 | 
 | ||||||
|             try { |             try { | ||||||
|                 $entity = $this->transformer->transform($record); |                 $entity = $this->transformer->transform($record); | ||||||
|  | 
 | ||||||
|  |                 if(!$entity) | ||||||
|  |                     continue; | ||||||
|  | 
 | ||||||
|                 $validator = $this->runValidation($entity); |                 $validator = $this->runValidation($entity); | ||||||
| 
 | 
 | ||||||
|                 if ($validator->fails()) { |                 if ($validator->fails()) { | ||||||
| @ -282,6 +286,8 @@ class BaseImport | |||||||
| 
 | 
 | ||||||
|     public function ingestInvoices($invoices, $invoice_number_key) |     public function ingestInvoices($invoices, $invoice_number_key) | ||||||
|     { |     { | ||||||
|  |         $count = 0; | ||||||
|  | 
 | ||||||
|         $invoice_transformer = $this->transformer; |         $invoice_transformer = $this->transformer; | ||||||
| 
 | 
 | ||||||
|         /** @var PaymentRepository $payment_repository */ |         /** @var PaymentRepository $payment_repository */ | ||||||
| @ -343,6 +349,7 @@ class BaseImport | |||||||
|                     } |                     } | ||||||
|                     $invoice_repository->save($invoice_data, $invoice); |                     $invoice_repository->save($invoice_data, $invoice); | ||||||
| 
 | 
 | ||||||
|  |                     $count++; | ||||||
|                     // If we're doing a generic CSV import, only import payment data if we're not importing a payment CSV.
 |                     // If we're doing a generic CSV import, only import payment data if we're not importing a payment CSV.
 | ||||||
|                     // If we're doing a platform-specific import, trust the platform to only return payment info if there's not a separate payment CSV.
 |                     // If we're doing a platform-specific import, trust the platform to only return payment info if there's not a separate payment CSV.
 | ||||||
|                     if ( |                     if ( | ||||||
| @ -404,6 +411,9 @@ class BaseImport | |||||||
|                 ]; |                 ]; | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|  | 
 | ||||||
|  |         return $count; | ||||||
|  | 
 | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     private function actionInvoiceStatus( |     private function actionInvoiceStatus( | ||||||
| @ -475,6 +485,8 @@ class BaseImport | |||||||
| 
 | 
 | ||||||
|     public function ingestQuotes($quotes, $quote_number_key) |     public function ingestQuotes($quotes, $quote_number_key) | ||||||
|     { |     { | ||||||
|  |         $count = 0; | ||||||
|  | 
 | ||||||
|         $quote_transformer = $this->transformer; |         $quote_transformer = $this->transformer; | ||||||
| 
 | 
 | ||||||
|         /** @var ClientRepository $client_repository */ |         /** @var ClientRepository $client_repository */ | ||||||
| @ -533,6 +545,8 @@ class BaseImport | |||||||
|                     } |                     } | ||||||
|                     $quote_repository->save($quote_data, $quote); |                     $quote_repository->save($quote_data, $quote); | ||||||
|                      |                      | ||||||
|  |                     $count++; | ||||||
|  | 
 | ||||||
|                     $this->actionQuoteStatus( |                     $this->actionQuoteStatus( | ||||||
|                         $quote, |                         $quote, | ||||||
|                         $quote_data, |                         $quote_data, | ||||||
| @ -552,7 +566,11 @@ class BaseImport | |||||||
|                     'error' => $message, |                     'error' => $message, | ||||||
|                 ]; |                 ]; | ||||||
|             } |             } | ||||||
|  | 
 | ||||||
|         } |         } | ||||||
|  | 
 | ||||||
|  |         return $count; | ||||||
|  | 
 | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     protected function getUserIDForRecord($record) |     protected function getUserIDForRecord($record) | ||||||
| @ -586,10 +604,11 @@ class BaseImport | |||||||
|         $data = [ |         $data = [ | ||||||
|             'errors'  => $this->error_array, |             'errors'  => $this->error_array, | ||||||
|             'company' => $this->company, |             'company' => $this->company, | ||||||
|  |             'entity_count' => $this->entity_count | ||||||
|         ]; |         ]; | ||||||
| 
 | 
 | ||||||
|         $nmo = new NinjaMailerObject; |         $nmo = new NinjaMailerObject; | ||||||
|         $nmo->mailable = new ImportCompleted($this->company, $data); |         $nmo->mailable = new CsvImportCompleted($this->company, $data); | ||||||
|         $nmo->company = $this->company; |         $nmo->company = $this->company; | ||||||
|         $nmo->settings = $this->company->settings; |         $nmo->settings = $this->company->settings; | ||||||
|         $nmo->to_user = $this->company->owner(); |         $nmo->to_user = $this->company->owner(); | ||||||
|  | |||||||
| @ -37,7 +37,7 @@ use App\Import\Transformer\Csv\PaymentTransformer; | |||||||
| use App\Import\Transformer\Csv\ProductTransformer; | use App\Import\Transformer\Csv\ProductTransformer; | ||||||
| use App\Import\Transformer\Csv\QuoteTransformer; | use App\Import\Transformer\Csv\QuoteTransformer; | ||||||
| use App\Import\Transformer\Csv\VendorTransformer; | use App\Import\Transformer\Csv\VendorTransformer; | ||||||
| use App\Import\Transformers\Bank\BankTransformer; | use App\Import\Transformer\Bank\BankTransformer; | ||||||
| use App\Repositories\BankTransactionRepository; | use App\Repositories\BankTransactionRepository; | ||||||
| use App\Repositories\ClientRepository; | use App\Repositories\ClientRepository; | ||||||
| use App\Repositories\ExpenseRepository; | use App\Repositories\ExpenseRepository; | ||||||
|  | |||||||
| @ -66,7 +66,6 @@ class Wave extends BaseImport implements ImportInterface | |||||||
| 
 | 
 | ||||||
|         if (empty($data)) { |         if (empty($data)) { | ||||||
|             $this->entity_count['clients'] = 0; |             $this->entity_count['clients'] = 0; | ||||||
| 
 |  | ||||||
|             return; |             return; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
| @ -170,11 +169,16 @@ class Wave extends BaseImport implements ImportInterface | |||||||
|         $entity_type = 'expense'; |         $entity_type = 'expense'; | ||||||
| 
 | 
 | ||||||
|         $data = $this->getCsvData($entity_type); |         $data = $this->getCsvData($entity_type); | ||||||
|  | 
 | ||||||
|  |         if(!$data){ | ||||||
|  |             $this->entity_count['expense'] = 0; | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|         $data = $this->preTransform($data, $entity_type); |         $data = $this->preTransform($data, $entity_type); | ||||||
| 
 | 
 | ||||||
|         if (empty($data)) { |         if (empty($data)) { | ||||||
|             $this->entity_count['expense'] = 0; |             $this->entity_count['expense'] = 0; | ||||||
| 
 |  | ||||||
|             return; |             return; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
| @ -212,6 +216,8 @@ class Wave extends BaseImport implements ImportInterface | |||||||
| 
 | 
 | ||||||
|     public function ingestExpenses($data) |     public function ingestExpenses($data) | ||||||
|     { |     { | ||||||
|  |         $count = 0; | ||||||
|  | 
 | ||||||
|         $key = 'Transaction ID'; |         $key = 'Transaction ID'; | ||||||
| 
 | 
 | ||||||
|         $expense_transformer = $this->transformer; |         $expense_transformer = $this->transformer; | ||||||
| @ -255,6 +261,7 @@ class Wave extends BaseImport implements ImportInterface | |||||||
|                     ); |                     ); | ||||||
| 
 | 
 | ||||||
|                     $expense_repository->save($expense_data, $expense); |                     $expense_repository->save($expense_data, $expense); | ||||||
|  |                     $count++; | ||||||
|                 } |                 } | ||||||
|             } catch (\Exception $ex) { |             } catch (\Exception $ex) { | ||||||
|                 if ($ex instanceof ImportException) { |                 if ($ex instanceof ImportException) { | ||||||
| @ -270,5 +277,8 @@ class Wave extends BaseImport implements ImportInterface | |||||||
|                 ]; |                 ]; | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|  | 
 | ||||||
|  |         return $count; | ||||||
|  | 
 | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | |||||||
| @ -9,7 +9,7 @@ | |||||||
|  * @license https://www.elastic.co/licensing/elastic-license |  * @license https://www.elastic.co/licensing/elastic-license | ||||||
|  */ |  */ | ||||||
| 
 | 
 | ||||||
| namespace App\Import\Transformers\Bank; | namespace App\Import\Transformer\Bank; | ||||||
| 
 | 
 | ||||||
| use App\Import\ImportException; | use App\Import\ImportException; | ||||||
| use App\Import\Transformer\BaseTransformer; | use App\Import\Transformer\BaseTransformer; | ||||||
| @ -61,9 +61,9 @@ class InvoiceTransformer extends BaseTransformer | |||||||
|                 'discount'           => $this->getFreshbookQuantityFloat($record, 'Discount Percentage'), |                 'discount'           => $this->getFreshbookQuantityFloat($record, 'Discount Percentage'), | ||||||
|                 'is_amount_discount' => false, |                 'is_amount_discount' => false, | ||||||
|                 'tax_name1'          => $this->getString($record, 'Tax 1 Type'), |                 'tax_name1'          => $this->getString($record, 'Tax 1 Type'), | ||||||
|                 'tax_rate1'          => $this->getFreshbookQuantityFloat($record, 'Tax 1 Amount'), |                 'tax_rate1'          => $this->calcTaxRate($record, 'Tax 1 Amount'), | ||||||
|                 'tax_name2'          => $this->getString($record, 'Tax 2 Type'), |                 'tax_name2'          => $this->getString($record, 'Tax 2 Type'), | ||||||
|                 'tax_rate2'          => $this->getFreshbookQuantityFloat($record, 'Tax 2 Amount'), |                 'tax_rate2'          => $this->calcTaxRate($record, 'Tax 2 Amount'), | ||||||
|             ]; |             ]; | ||||||
|             $transformed['amount'] += $this->getFreshbookQuantityFloat($record, 'Line Total'); |             $transformed['amount'] += $this->getFreshbookQuantityFloat($record, 'Line Total'); | ||||||
|         } |         } | ||||||
| @ -79,6 +79,27 @@ class InvoiceTransformer extends BaseTransformer | |||||||
|         return $transformed; |         return $transformed; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     //Line Subtotal
 | ||||||
|  |     public function calcTaxRate($record, $field) | ||||||
|  |     { | ||||||
|  |         if(isset($record['Line Subtotal']) && $record['Line Subtotal'] > 0) | ||||||
|  |             return ($record[$field] / $record['Line Subtotal']) * 100; | ||||||
|  | 
 | ||||||
|  |         $tax_amount1 = isset($record['Tax 1 Amount']) ? $record['Tax 1 Amount'] : 0; | ||||||
|  | 
 | ||||||
|  |         $tax_amount2 = isset($record['Tax 2 Amount']) ? $record['Tax 2 Amount'] : 0; | ||||||
|  | 
 | ||||||
|  |         $line_total = isset($record['Line Total']) ? $record['Line Total'] : 0; | ||||||
|  | 
 | ||||||
|  |         $subtotal = $line_total - $tax_amount2 - $tax_amount1; | ||||||
|  | 
 | ||||||
|  |         if($subtotal > 0) | ||||||
|  |             return $record[$field] / $subtotal * 100; | ||||||
|  | 
 | ||||||
|  |         return 0; | ||||||
|  | 
 | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     /** @return float  */ |     /** @return float  */ | ||||||
|     public function getFreshbookQuantityFloat($data, $field) |     public function getFreshbookQuantityFloat($data, $field) | ||||||
|     { |     { | ||||||
|  | |||||||
| @ -28,6 +28,11 @@ class InvoiceTransformer extends BaseTransformer | |||||||
|      */ |      */ | ||||||
|     public function transform($invoice_data) |     public function transform($invoice_data) | ||||||
|     { |     { | ||||||
|  | 
 | ||||||
|  |         if (!isset($invoice_data['DocumentNumber'])) { | ||||||
|  |             throw new ImportException('DocumentNumber key not found in this import file.'); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|         if ($this->hasInvoice($invoice_data['DocumentNumber'])) { |         if ($this->hasInvoice($invoice_data['DocumentNumber'])) { | ||||||
|             throw new ImportException('Invoice number already exists'); |             throw new ImportException('Invoice number already exists'); | ||||||
|         } |         } | ||||||
|  | |||||||
| @ -28,7 +28,8 @@ class ClientTransformer extends BaseTransformer | |||||||
|     public function transform($data) |     public function transform($data) | ||||||
|     { |     { | ||||||
|         if (isset($data['customer_name']) && $this->hasClient($data['customer_name'])) { |         if (isset($data['customer_name']) && $this->hasClient($data['customer_name'])) { | ||||||
|             throw new ImportException('Client already exists'); |             return false; | ||||||
|  |             // throw new ImportException('Client already exists');
 | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         $settings = new \stdClass; |         $settings = new \stdClass; | ||||||
|  | |||||||
| @ -1,430 +0,0 @@ | |||||||
| <?php |  | ||||||
| /** |  | ||||||
|  * Invoice Ninja (https://invoiceninja.com). |  | ||||||
|  * |  | ||||||
|  * @link https://github.com/invoiceninja/invoiceninja source repository |  | ||||||
|  * |  | ||||||
|  * @copyright Copyright (c) 2022. Invoice Ninja LLC (https://invoiceninja.com) |  | ||||||
|  * |  | ||||||
|  * @license https://www.elastic.co/licensing/elastic-license |  | ||||||
|  */ |  | ||||||
| 
 |  | ||||||
| namespace App\Import\Transformers; |  | ||||||
| 
 |  | ||||||
| use App\Models\ClientContact; |  | ||||||
| use App\Utils\Number; |  | ||||||
| use Carbon; |  | ||||||
| use Exception; |  | ||||||
| 
 |  | ||||||
| /** |  | ||||||
|  * Class BaseTransformer. |  | ||||||
|  */ |  | ||||||
| class BaseTransformer |  | ||||||
| { |  | ||||||
|     /** |  | ||||||
|      * @var |  | ||||||
|      */ |  | ||||||
|     protected $maps; |  | ||||||
| 
 |  | ||||||
|     /** |  | ||||||
|      * BaseTransformer constructor. |  | ||||||
|      * |  | ||||||
|      * @param $maps |  | ||||||
|      */ |  | ||||||
|     public function __construct($maps) |  | ||||||
|     { |  | ||||||
|         $this->maps = $maps; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     /** |  | ||||||
|      * @param $data |  | ||||||
|      * @param $field |  | ||||||
|      * |  | ||||||
|      * @return string |  | ||||||
|      */ |  | ||||||
|     public function getString($data, $field) |  | ||||||
|     { |  | ||||||
|         return (isset($data[$field]) && $data[$field]) ? $data[$field] : ''; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     public function getInvoiceTypeId($data, $field) |  | ||||||
|     { |  | ||||||
|         return (isset($data[$field]) && $data[$field]) ? $data[$field] : '1'; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     public function getCurrencyByCode($data, $key = 'client.currency_id') |  | ||||||
|     { |  | ||||||
|         $code = array_key_exists($key, $data) ? $data[$key] : false; |  | ||||||
| 
 |  | ||||||
|         return $this->maps['currencies'][$code] ?? $this->maps['company']->settings->currency_id; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     public function getClient($client_name, $client_email) |  | ||||||
|     { |  | ||||||
|         $clients = $this->maps['company']->clients; |  | ||||||
| 
 |  | ||||||
|         $client_id_search = $clients->where('id_number', $client_name); |  | ||||||
| 
 |  | ||||||
|         if ($client_id_search->count() >= 1) { |  | ||||||
|             return $client_id_search->first()->id; |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         $client_name_search = $clients->where('name', $client_name); |  | ||||||
| 
 |  | ||||||
|         if ($client_name_search->count() >= 1) { |  | ||||||
|             return $client_name_search->first()->id; |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         if (! empty($client_email)) { |  | ||||||
|             $contacts = ClientContact::where('company_id', $this->maps['company']->id) |  | ||||||
|                                      ->where('email', $client_email); |  | ||||||
| 
 |  | ||||||
|             if ($contacts->count() >= 1) { |  | ||||||
|                 return $contacts->first()->client_id; |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         return null; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     ///////////////////////////////////////////////////////////////////////////////////
 |  | ||||||
|     /** |  | ||||||
|      * @param $name |  | ||||||
|      * |  | ||||||
|      * @return bool |  | ||||||
|      */ |  | ||||||
|     public function hasClient($name) |  | ||||||
|     { |  | ||||||
|         $name = trim(strtolower($name)); |  | ||||||
| 
 |  | ||||||
|         return isset($this->maps['client'][$name]); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     /** |  | ||||||
|      * @param $name |  | ||||||
|      * |  | ||||||
|      * @return bool |  | ||||||
|      */ |  | ||||||
|     public function hasVendor($name) |  | ||||||
|     { |  | ||||||
|         $name = trim(strtolower($name)); |  | ||||||
| 
 |  | ||||||
|         return isset($this->maps['vendor'][$name]); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     /** |  | ||||||
|      * @param $key |  | ||||||
|      * |  | ||||||
|      * @return bool |  | ||||||
|      */ |  | ||||||
|     public function hasProduct($key) |  | ||||||
|     { |  | ||||||
|         $key = trim(strtolower($key)); |  | ||||||
| 
 |  | ||||||
|         return isset($this->maps['product'][$key]); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     /** |  | ||||||
|      * @param $data |  | ||||||
|      * @param $field |  | ||||||
|      * |  | ||||||
|      * @return int |  | ||||||
|      */ |  | ||||||
|     public function getNumber($data, $field) |  | ||||||
|     { |  | ||||||
|         return (isset($data->$field) && $data->$field) ? $data->$field : 0; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     /** |  | ||||||
|      * @param $data |  | ||||||
|      * @param $field |  | ||||||
|      * |  | ||||||
|      * @return float |  | ||||||
|      */ |  | ||||||
|     public function getFloat($data, $field) |  | ||||||
|     { |  | ||||||
|         if (array_key_exists($field, $data)) { |  | ||||||
|             $number = preg_replace('/[^0-9-.]+/', '', $data[$field]); |  | ||||||
|         } else { |  | ||||||
|             $number = 0; |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         return Number::parseFloat($number); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     public function getFloatWithSamePrecision($data, $field) |  | ||||||
|     { |  | ||||||
|         $precision = (int) strpos(strrev($data[$field]), "."); |  | ||||||
| 
 |  | ||||||
|         return round($data[$field], $precision); |  | ||||||
|     } |  | ||||||
|     /** |  | ||||||
|      * @param $name |  | ||||||
|      * |  | ||||||
|      * @return null |  | ||||||
|      */ |  | ||||||
|     public function getClientId($name) |  | ||||||
|     { |  | ||||||
|         $name = strtolower(trim($name)); |  | ||||||
| 
 |  | ||||||
|         return isset($this->maps['client'][$name]) ? $this->maps['client'][$name] : null; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     /** |  | ||||||
|      * @param $name |  | ||||||
|      * |  | ||||||
|      * @return null |  | ||||||
|      */ |  | ||||||
|     public function getProduct($data, $key, $field, $default = false) |  | ||||||
|     { |  | ||||||
|         $productKey = trim(strtolower($data->$key)); |  | ||||||
| 
 |  | ||||||
|         if (! isset($this->maps['product'][$productKey])) { |  | ||||||
|             return $default; |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         $product = $this->maps['product'][$productKey]; |  | ||||||
| 
 |  | ||||||
|         return $product->$field ?: $default; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     /** |  | ||||||
|      * @param $name |  | ||||||
|      * |  | ||||||
|      * @return null |  | ||||||
|      */ |  | ||||||
|     public function getContact($email) |  | ||||||
|     { |  | ||||||
|         $email = trim(strtolower($email)); |  | ||||||
| 
 |  | ||||||
|         if (! isset($this->maps['contact'][$email])) { |  | ||||||
|             return false; |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         return $this->maps['contact'][$email]; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     /** |  | ||||||
|      * @param $name |  | ||||||
|      * |  | ||||||
|      * @return null |  | ||||||
|      */ |  | ||||||
|     public function getCustomer($key) |  | ||||||
|     { |  | ||||||
|         $key = trim($key); |  | ||||||
| 
 |  | ||||||
|         if (! isset($this->maps['customer'][$key])) { |  | ||||||
|             return false; |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         return $this->maps['customer'][$key]; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     /** |  | ||||||
|      * @param $name |  | ||||||
|      * |  | ||||||
|      * @return null |  | ||||||
|      */ |  | ||||||
|     public function getCountryId($name) |  | ||||||
|     { |  | ||||||
|         $name = strtolower(trim($name)); |  | ||||||
| 
 |  | ||||||
|         if (strlen($name) == 2) { |  | ||||||
|             return $this->getCountryIdBy2($name); |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         return isset($this->maps['countries'][$name]) ? $this->maps['countries'][$name] : null; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     /** |  | ||||||
|      * @param $name |  | ||||||
|      * |  | ||||||
|      * @return null |  | ||||||
|      */ |  | ||||||
|     public function getCountryIdBy2($name) |  | ||||||
|     { |  | ||||||
|         $name = strtolower(trim($name)); |  | ||||||
| 
 |  | ||||||
|         return isset($this->maps['countries2'][$name]) ? $this->maps['countries2'][$name] : null; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     /** |  | ||||||
|      * @param $name |  | ||||||
|      * |  | ||||||
|      * @return null |  | ||||||
|      */ |  | ||||||
|     public function getTaxRate($name) |  | ||||||
|     { |  | ||||||
|         $name = strtolower(trim($name)); |  | ||||||
| 
 |  | ||||||
|         return isset($this->maps['tax_rates'][$name]) ? $this->maps['tax_rates'][$name] : 0; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     /** |  | ||||||
|      * @param $name |  | ||||||
|      * |  | ||||||
|      * @return null |  | ||||||
|      */ |  | ||||||
|     public function getTaxName($name) |  | ||||||
|     { |  | ||||||
|         $name = strtolower(trim($name)); |  | ||||||
| 
 |  | ||||||
|         return isset($this->maps['tax_names'][$name]) ? $this->maps['tax_names'][$name] : ''; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     /** |  | ||||||
|      * @param $name |  | ||||||
|      * |  | ||||||
|      * @return mixed |  | ||||||
|      */ |  | ||||||
|     public function getFirstName($name) |  | ||||||
|     { |  | ||||||
|         $name = Utils::splitName($name); |  | ||||||
| 
 |  | ||||||
|         return $name[0]; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     /** |  | ||||||
|      * @param $date |  | ||||||
|      * @param string $format |  | ||||||
|      * @param mixed  $data |  | ||||||
|      * @param mixed  $field |  | ||||||
|      * |  | ||||||
|      * @return null |  | ||||||
|      */ |  | ||||||
|     public function getDate($data, $field) |  | ||||||
|     { |  | ||||||
|         if ($date = data_get($data, $field)) { |  | ||||||
|             try { |  | ||||||
|                 $date = new Carbon($date); |  | ||||||
|             } catch (Exception $e) { |  | ||||||
|                 // if we fail to parse return blank
 |  | ||||||
|                 $date = false; |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         return $date ? $date->format('Y-m-d') : null; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     /** |  | ||||||
|      * @param $name |  | ||||||
|      * |  | ||||||
|      * @return mixed |  | ||||||
|      */ |  | ||||||
|     public function getLastName($name) |  | ||||||
|     { |  | ||||||
|         $name = Utils::splitName($name); |  | ||||||
| 
 |  | ||||||
|         return $name[1]; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     /** |  | ||||||
|      * @param $number |  | ||||||
|      * |  | ||||||
|      * @return string |  | ||||||
|      */ |  | ||||||
|     public function getInvoiceNumber($number) |  | ||||||
|     { |  | ||||||
|         return $number ? ltrim(trim($number), '0') : null; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     /** |  | ||||||
|      * @param $invoiceNumber |  | ||||||
|      * |  | ||||||
|      * @return null |  | ||||||
|      */ |  | ||||||
|     public function getInvoiceId($invoiceNumber) |  | ||||||
|     { |  | ||||||
|         $invoiceNumber = $this->getInvoiceNumber($invoiceNumber); |  | ||||||
|         $invoiceNumber = strtolower($invoiceNumber); |  | ||||||
| 
 |  | ||||||
|         return isset($this->maps['invoice'][$invoiceNumber]) ? $this->maps['invoice'][$invoiceNumber] : null; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     /** |  | ||||||
|      * @param $invoiceNumber |  | ||||||
|      * |  | ||||||
|      * @return null |  | ||||||
|      */ |  | ||||||
|     public function getInvoicePublicId($invoiceNumber) |  | ||||||
|     { |  | ||||||
|         $invoiceNumber = $this->getInvoiceNumber($invoiceNumber); |  | ||||||
|         $invoiceNumber = strtolower($invoiceNumber); |  | ||||||
| 
 |  | ||||||
|         return isset($this->maps['invoice'][$invoiceNumber]) ? $this->maps['invoices'][$invoiceNumber]->public_id : null; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     /** |  | ||||||
|      * @param $invoiceNumber |  | ||||||
|      * |  | ||||||
|      * @return bool |  | ||||||
|      */ |  | ||||||
|     public function hasInvoice($invoiceNumber) |  | ||||||
|     { |  | ||||||
|         $invoiceNumber = $this->getInvoiceNumber($invoiceNumber); |  | ||||||
|         $invoiceNumber = strtolower($invoiceNumber); |  | ||||||
| 
 |  | ||||||
|         return $this->maps['invoice'][$invoiceNumber] ?? null; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     /** |  | ||||||
|      * @param $invoiceNumber |  | ||||||
|      * |  | ||||||
|      * @return null |  | ||||||
|      */ |  | ||||||
|     public function getInvoiceClientId($invoiceNumber) |  | ||||||
|     { |  | ||||||
|         $invoiceNumber = $this->getInvoiceNumber($invoiceNumber); |  | ||||||
|         $invoiceNumber = strtolower($invoiceNumber); |  | ||||||
| 
 |  | ||||||
|         return $this->maps['invoice_client'][$invoiceNumber] ?? null; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     /** |  | ||||||
|      * @param $name |  | ||||||
|      * |  | ||||||
|      * @return null |  | ||||||
|      */ |  | ||||||
|     public function getVendorId($name) |  | ||||||
|     { |  | ||||||
|         $name = strtolower(trim($name)); |  | ||||||
| 
 |  | ||||||
|         return $this->maps['vendor'][$name] ?? null; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     /** |  | ||||||
|      * @param $name |  | ||||||
|      * |  | ||||||
|      * @return null |  | ||||||
|      */ |  | ||||||
|     public function getExpenseCategoryId($name) |  | ||||||
|     { |  | ||||||
|         $name = strtolower(trim($name)); |  | ||||||
| 
 |  | ||||||
|         return $this->maps['expense_category'][$name] ?? null; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     /** |  | ||||||
|      * @param $name |  | ||||||
|      * |  | ||||||
|      * @return null |  | ||||||
|      */ |  | ||||||
|     public function getProjectId($name) |  | ||||||
|     { |  | ||||||
|         $name = strtolower(trim($name)); |  | ||||||
| 
 |  | ||||||
|         return $this->maps['project'][$name] ?? null; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     /** |  | ||||||
|      * @param $name |  | ||||||
|      * |  | ||||||
|      * @return null |  | ||||||
|      */ |  | ||||||
|     public function getPaymentTypeId($name) |  | ||||||
|     { |  | ||||||
|         $name = strtolower(trim($name)); |  | ||||||
| 
 |  | ||||||
|         return $this->maps['payment_type'][$name] ?? null; |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @ -1,78 +0,0 @@ | |||||||
| <?php |  | ||||||
| /** |  | ||||||
|  * Invoice Ninja (https://invoiceninja.com). |  | ||||||
|  * |  | ||||||
|  * @link https://github.com/invoiceninja/invoiceninja source repository |  | ||||||
|  * |  | ||||||
|  * @copyright Copyright (c) 2022. Invoice Ninja LLC (https://invoiceninja.com) |  | ||||||
|  * |  | ||||||
|  * @license https://www.elastic.co/licensing/elastic-license |  | ||||||
|  */ |  | ||||||
| 
 |  | ||||||
| namespace App\Import\Transformers; |  | ||||||
| 
 |  | ||||||
| use Illuminate\Support\Str; |  | ||||||
| 
 |  | ||||||
| /** |  | ||||||
|  * Class ClientTransformer. |  | ||||||
|  */ |  | ||||||
| class ClientTransformer extends BaseTransformer |  | ||||||
| { |  | ||||||
|     /** |  | ||||||
|      * @param $data |  | ||||||
|      * |  | ||||||
|      * @return bool|Item |  | ||||||
|      */ |  | ||||||
|     public function transform($data) |  | ||||||
|     { |  | ||||||
|         if (isset($data->name) && $this->hasClient($data->name)) { |  | ||||||
|             return false; |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         $settings = new \stdClass; |  | ||||||
|         $settings->currency_id = (string) $this->getCurrencyByCode($data); |  | ||||||
| 
 |  | ||||||
|         return [ |  | ||||||
|             'company_id' => $this->maps['company']->id, |  | ||||||
|             'name' => $this->getString($data, 'client.name'), |  | ||||||
|             'phone' => $this->getString($data, 'client.phone'), |  | ||||||
|             'address1' => $this->getString($data, 'client.address1'), |  | ||||||
|             'address2' => $this->getString($data, 'client.address2'), |  | ||||||
|             'city' => $this->getString($data, 'client.city'), |  | ||||||
|             'state' => $this->getString($data, 'client.state'), |  | ||||||
|             'shipping_address1' => $this->getString($data, 'client.shipping_address1'), |  | ||||||
|             'shipping_address2' => $this->getString($data, 'client.shipping_address2'), |  | ||||||
|             'shipping_city' => $this->getString($data, 'client.shipping_city'), |  | ||||||
|             'shipping_state' => $this->getString($data, 'client.shipping_state'), |  | ||||||
|             'shipping_postal_code' => $this->getString($data, 'client.shipping_postal_code'), |  | ||||||
|             'public_notes' => $this->getString($data, 'client.public_notes'), |  | ||||||
|             'private_notes' => $this->getString($data, 'client.private_notes'), |  | ||||||
|             'website' => $this->getString($data, 'client.website'), |  | ||||||
|             'vat_number' => $this->getString($data, 'client.vat_number'), |  | ||||||
|             'id_number' => $this->getString($data, 'client.id_number'), |  | ||||||
|             'custom_value1' => $this->getString($data, 'client.custom1'), |  | ||||||
|             'custom_value2' => $this->getString($data, 'client.custom2'), |  | ||||||
|             'custom_value3' => $this->getString($data, 'client.custom3'), |  | ||||||
|             'custom_value4' => $this->getString($data, 'client.custom4'), |  | ||||||
|             'balance' => $this->getFloat($data, 'client.balance'), |  | ||||||
|             'paid_to_date' => $this->getFloat($data, 'client.paid_to_date'), |  | ||||||
|             'credit_balance' => 0, |  | ||||||
|             'settings' => $settings, |  | ||||||
|             'client_hash' => Str::random(40), |  | ||||||
|             'contacts' => [ |  | ||||||
|                 [ |  | ||||||
|                     'first_name' => $this->getString($data, 'contact.first_name'), |  | ||||||
|                     'last_name' => $this->getString($data, 'contact.last_name'), |  | ||||||
|                     'email' => $this->getString($data, 'contact.email'), |  | ||||||
|                     'phone' => $this->getString($data, 'contact.phone'), |  | ||||||
|                     'custom_value1' => $this->getString($data, 'contact.custom1'), |  | ||||||
|                     'custom_value2' => $this->getString($data, 'contact.custom2'), |  | ||||||
|                     'custom_value3' => $this->getString($data, 'contact.custom3'), |  | ||||||
|                     'custom_value4' => $this->getString($data, 'contact.custom4'), |  | ||||||
|                 ], |  | ||||||
|             ], |  | ||||||
|             'country_id' => isset($data->country_id) ? $this->getCountryId($data->country_id) : null, |  | ||||||
|             'shipping_country_id' => isset($data->shipping_country_id) ? $this->getCountryId($data->shipping_country_id) : null, |  | ||||||
|         ]; |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @ -1,120 +0,0 @@ | |||||||
| <?php |  | ||||||
| /** |  | ||||||
|  * client Ninja (https://clientninja.com). |  | ||||||
|  * |  | ||||||
|  * @link https://github.com/clientninja/clientninja source repository |  | ||||||
|  * |  | ||||||
|  * @copyright Copyright (c) 2022. client Ninja LLC (https://clientninja.com) |  | ||||||
|  * |  | ||||||
|  * @license https://www.elastic.co/licensing/elastic-license |  | ||||||
|  */ |  | ||||||
| 
 |  | ||||||
| namespace App\Import\Transformers\Csv; |  | ||||||
| 
 |  | ||||||
| use App\Import\ImportException; |  | ||||||
| use App\Import\Transformers\BaseTransformer; |  | ||||||
| use Illuminate\Support\Str; |  | ||||||
| 
 |  | ||||||
| /** |  | ||||||
|  * Class ClientTransformer. |  | ||||||
|  */ |  | ||||||
| class ClientTransformer extends BaseTransformer |  | ||||||
| { |  | ||||||
|     /** |  | ||||||
|      * @param $data |  | ||||||
|      * |  | ||||||
|      * @return array|bool |  | ||||||
|      */ |  | ||||||
|     public function transform($data) |  | ||||||
|     { |  | ||||||
|         if (isset($data->name) && $this->hasClient($data->name)) { |  | ||||||
|             throw new ImportException('Client already exists'); |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         $settings = new \stdClass(); |  | ||||||
|         $settings->currency_id = (string) $this->getCurrencyByCode($data); |  | ||||||
| 
 |  | ||||||
|         return [ |  | ||||||
|             'company_id' => $this->maps['company']->id, |  | ||||||
|             'name' => $this->getString($data, 'client.name'), |  | ||||||
|             'phone' => $this->getString($data, 'client.phone'), |  | ||||||
|             'address1' => $this->getString($data, 'client.address1'), |  | ||||||
|             'address2' => $this->getString($data, 'client.address2'), |  | ||||||
|             'postal_code' => $this->getString($data, 'client.postal_code'), |  | ||||||
|             'city' => $this->getString($data, 'client.city'), |  | ||||||
|             'state' => $this->getString($data, 'client.state'), |  | ||||||
|             'shipping_address1' => $this->getString( |  | ||||||
|                 $data, |  | ||||||
|                 'client.shipping_address1' |  | ||||||
|             ), |  | ||||||
|             'shipping_address2' => $this->getString( |  | ||||||
|                 $data, |  | ||||||
|                 'client.shipping_address2' |  | ||||||
|             ), |  | ||||||
|             'shipping_city' => $this->getString($data, 'client.shipping_city'), |  | ||||||
|             'shipping_state' => $this->getString( |  | ||||||
|                 $data, |  | ||||||
|                 'client.shipping_state' |  | ||||||
|             ), |  | ||||||
|             'shipping_postal_code' => $this->getString( |  | ||||||
|                 $data, |  | ||||||
|                 'client.shipping_postal_code' |  | ||||||
|             ), |  | ||||||
|             'public_notes' => $this->getString($data, 'client.public_notes'), |  | ||||||
|             'private_notes' => $this->getString($data, 'client.private_notes'), |  | ||||||
|             'website' => $this->getString($data, 'client.website'), |  | ||||||
|             'vat_number' => $this->getString($data, 'client.vat_number'), |  | ||||||
|             'id_number' => $this->getString($data, 'client.id_number'), |  | ||||||
|             'custom_value1' => $this->getString($data, 'client.custom_value1'), |  | ||||||
|             'custom_value2' => $this->getString($data, 'client.custom_value2'), |  | ||||||
|             'custom_value3' => $this->getString($data, 'client.custom_value3'), |  | ||||||
|             'custom_value4' => $this->getString($data, 'client.custom_value4'), |  | ||||||
|             'balance' => preg_replace( |  | ||||||
|                 '/[^0-9,.]+/', |  | ||||||
|                 '', |  | ||||||
|                 $this->getFloat($data, 'client.balance') |  | ||||||
|             ), |  | ||||||
|             'paid_to_date' => preg_replace( |  | ||||||
|                 '/[^0-9,.]+/', |  | ||||||
|                 '', |  | ||||||
|                 $this->getFloat($data, 'client.paid_to_date') |  | ||||||
|             ), |  | ||||||
|             'credit_balance' => 0, |  | ||||||
|             'settings' => $settings, |  | ||||||
|             'client_hash' => Str::random(40), |  | ||||||
|             'contacts' => [ |  | ||||||
|                 [ |  | ||||||
|                     'first_name' => $this->getString( |  | ||||||
|                         $data, |  | ||||||
|                         'contact.first_name' |  | ||||||
|                     ), |  | ||||||
|                     'last_name' => $this->getString($data, 'contact.last_name'), |  | ||||||
|                     'email' => $this->getString($data, 'contact.email'), |  | ||||||
|                     'phone' => $this->getString($data, 'contact.phone'), |  | ||||||
|                     'custom_value1' => $this->getString( |  | ||||||
|                         $data, |  | ||||||
|                         'contact.custom_value1' |  | ||||||
|                     ), |  | ||||||
|                     'custom_value2' => $this->getString( |  | ||||||
|                         $data, |  | ||||||
|                         'contact.custom_value2' |  | ||||||
|                     ), |  | ||||||
|                     'custom_value3' => $this->getString( |  | ||||||
|                         $data, |  | ||||||
|                         'contact.custom_value3' |  | ||||||
|                     ), |  | ||||||
|                     'custom_value4' => $this->getString( |  | ||||||
|                         $data, |  | ||||||
|                         'contact.custom_value4' |  | ||||||
|                     ), |  | ||||||
|                 ], |  | ||||||
|             ], |  | ||||||
|             'country_id' => isset($data['client.country']) |  | ||||||
|                 ? $this->getCountryId($data['client.country']) |  | ||||||
|                 : null, |  | ||||||
|             'shipping_country_id' => isset($data['client.shipping_country']) |  | ||||||
|                 ? $this->getCountryId($data['client.shipping_country']) |  | ||||||
|                 : null, |  | ||||||
|         ]; |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @ -1,42 +0,0 @@ | |||||||
| <?php |  | ||||||
| 
 |  | ||||||
| namespace App\Import\Transformers\Csv; |  | ||||||
| 
 |  | ||||||
| use App\Import\Transformers\BaseTransformer; |  | ||||||
| 
 |  | ||||||
| /** |  | ||||||
|  * Class InvoiceTransformer. |  | ||||||
|  */ |  | ||||||
| class ExpenseTransformer extends BaseTransformer |  | ||||||
| { |  | ||||||
|     /** |  | ||||||
|      * @param $data |  | ||||||
|      * |  | ||||||
|      * @return bool|array |  | ||||||
|      */ |  | ||||||
|     public function transform($data) |  | ||||||
|     { |  | ||||||
|         $clientId = isset($data['expense.client']) ? $this->getClientId($data['expense.client']) : null; |  | ||||||
| 
 |  | ||||||
|         return [ |  | ||||||
|             'company_id'            => $this->maps['company']->id, |  | ||||||
|             'amount'                => $this->getFloat($data, 'expense.amount'), |  | ||||||
|             'currency_id'           => $this->getCurrencyByCode($data, 'expense.currency_id'), |  | ||||||
|             'vendor_id'             => isset($data['expense.vendor']) ? $this->getVendorId($data['expense.vendor']) : null, |  | ||||||
|             'client_id'             => isset($data['expense.client']) ? $this->getClientId($data['expense.client']) : null, |  | ||||||
|             'date'		            => isset($data['expense.date']) ? date('Y-m-d', strtotime($data['expense.date'])) : null, |  | ||||||
|             'public_notes'          => $this->getString($data, 'expense.public_notes'), |  | ||||||
|             'private_notes'         => $this->getString($data, 'expense.private_notes'), |  | ||||||
|             'category_id'   		=> isset($data['expense.category']) ? $this->getExpenseCategoryId($data['expense.category']) : null, |  | ||||||
|             'project_id'            => isset($data['expense.project']) ? $this->getProjectId($data['expense.project']) : null, |  | ||||||
|             'payment_type_id'       => isset($data['expense.payment_type']) ? $this->getPaymentTypeId($data['expense.payment_type']) : null, |  | ||||||
|             'payment_date'          => isset($data['expense.payment_date']) ? date('Y-m-d', strtotime($data['expense.payment_date'])) : null, |  | ||||||
|             'custom_value1'        => $this->getString($data, 'expense.custom_value1'), |  | ||||||
|             'custom_value2'        => $this->getString($data, 'expense.custom_value2'), |  | ||||||
|             'custom_value3'        => $this->getString($data, 'expense.custom_value3'), |  | ||||||
|             'custom_value4'        => $this->getString($data, 'expense.custom_value4'), |  | ||||||
|             'transaction_reference' => $this->getString($data, 'expense.transaction_reference'), |  | ||||||
|             'should_be_invoiced'    => $clientId ? true : false, |  | ||||||
|         ]; |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @ -1,133 +0,0 @@ | |||||||
| <?php |  | ||||||
| /** |  | ||||||
|  * client Ninja (https://clientninja.com). |  | ||||||
|  * |  | ||||||
|  * @link https://github.com/clientninja/clientninja source repository |  | ||||||
|  * |  | ||||||
|  * @copyright Copyright (c) 2022. client Ninja LLC (https://clientninja.com) |  | ||||||
|  * |  | ||||||
|  * @license https://www.elastic.co/licensing/elastic-license |  | ||||||
|  */ |  | ||||||
| 
 |  | ||||||
| namespace App\Import\Transformers\Csv; |  | ||||||
| 
 |  | ||||||
| use App\Import\ImportException; |  | ||||||
| use App\Import\Transformers\BaseTransformer; |  | ||||||
| use App\Models\Invoice; |  | ||||||
| 
 |  | ||||||
| /** |  | ||||||
|  * Class InvoiceTransformer. |  | ||||||
|  */ |  | ||||||
| class InvoiceTransformer extends BaseTransformer |  | ||||||
| { |  | ||||||
|     /** |  | ||||||
|      * @param $data |  | ||||||
|      * |  | ||||||
|      * @return bool|array |  | ||||||
|      */ |  | ||||||
|     public function transform($line_items_data) |  | ||||||
|     { |  | ||||||
|         $invoice_data = reset($line_items_data); |  | ||||||
| 
 |  | ||||||
|         if ($this->hasInvoice($invoice_data['invoice.number'])) { |  | ||||||
|             throw new ImportException('Invoice number already exists'); |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         $invoiceStatusMap = [ |  | ||||||
|             'sent'  => Invoice::STATUS_SENT, |  | ||||||
|             'draft' => Invoice::STATUS_DRAFT, |  | ||||||
|         ]; |  | ||||||
| 
 |  | ||||||
|         $transformed = [ |  | ||||||
|             'company_id'        => $this->maps['company']->id, |  | ||||||
|             'number'            => $this->getString($invoice_data, 'invoice.number'), |  | ||||||
|             'user_id'           => $this->getString($invoice_data, 'invoice.user_id'), |  | ||||||
|             'amount'            => $amount = $this->getFloat($invoice_data, 'invoice.amount'), |  | ||||||
|             'balance'           => isset($invoice_data['invoice.balance']) ? $this->getFloat($invoice_data, 'invoice.balance') : $amount, |  | ||||||
|             'client_id'         => $this->getClient($this->getString($invoice_data, 'client.name'), $this->getString($invoice_data, 'client.email')), |  | ||||||
|             'discount'          => $this->getFloat($invoice_data, 'invoice.discount'), |  | ||||||
|             'po_number'         => $this->getString($invoice_data, 'invoice.po_number'), |  | ||||||
|             'date'              => isset($invoice_data['invoice.date']) ? date('Y-m-d', strtotime($invoice_data['invoice.date'])) : now()->format('Y-m-d'), |  | ||||||
|             'due_date'          => isset($invoice_data['invoice.due_date']) ? date('Y-m-d', strtotime($invoice_data['invoice.due_date'])) : null, |  | ||||||
|             'terms'             => $this->getString($invoice_data, 'invoice.terms'), |  | ||||||
|             'public_notes'      => $this->getString($invoice_data, 'invoice.public_notes'), |  | ||||||
|             // 'is_sent'           => $this->getString( $invoice_data, 'invoice.is_sent' ),
 |  | ||||||
|             'private_notes'     => $this->getString($invoice_data, 'invoice.private_notes'), |  | ||||||
|             'tax_name1'         => $this->getString($invoice_data, 'invoice.tax_name1'), |  | ||||||
|             'tax_rate1'         => $this->getFloat($invoice_data, 'invoice.tax_rate1'), |  | ||||||
|             'tax_name2'         => $this->getString($invoice_data, 'invoice.tax_name2'), |  | ||||||
|             'tax_rate2'         => $this->getFloat($invoice_data, 'invoice.tax_rate2'), |  | ||||||
|             'tax_name3'         => $this->getString($invoice_data, 'invoice.tax_name3'), |  | ||||||
|             'tax_rate3'         => $this->getFloat($invoice_data, 'invoice.tax_rate3'), |  | ||||||
|             'custom_value1'     => $this->getString($invoice_data, 'invoice.custom_value1'), |  | ||||||
|             'custom_value2'     => $this->getString($invoice_data, 'invoice.custom_value2'), |  | ||||||
|             'custom_value3'     => $this->getString($invoice_data, 'invoice.custom_value3'), |  | ||||||
|             'custom_value4'     => $this->getString($invoice_data, 'invoice.custom_value4'), |  | ||||||
|             'footer'            => $this->getString($invoice_data, 'invoice.footer'), |  | ||||||
|             'partial'           => $this->getFloat($invoice_data, 'invoice.partial'), |  | ||||||
|             'partial_due_date'  => $this->getString($invoice_data, 'invoice.partial_due_date'), |  | ||||||
|             'custom_surcharge1' => $this->getString($invoice_data, 'invoice.custom_surcharge1'), |  | ||||||
|             'custom_surcharge2' => $this->getString($invoice_data, 'invoice.custom_surcharge2'), |  | ||||||
|             'custom_surcharge3' => $this->getString($invoice_data, 'invoice.custom_surcharge3'), |  | ||||||
|             'custom_surcharge4' => $this->getString($invoice_data, 'invoice.custom_surcharge4'), |  | ||||||
|             'exchange_rate'     => $this->getString($invoice_data, 'invoice.exchange_rate'), |  | ||||||
|             'status_id'         => $invoiceStatusMap[$status = |  | ||||||
|                     strtolower($this->getString($invoice_data, 'invoice.status'))] ?? |  | ||||||
|                 Invoice::STATUS_SENT, |  | ||||||
|             // 'viewed'            => $status === 'viewed',
 |  | ||||||
|             'archived'          => $status === 'archived', |  | ||||||
|         ]; |  | ||||||
| 
 |  | ||||||
|         if (isset($invoice_data['payment.amount'])) { |  | ||||||
|             $transformed['payments'] = [ |  | ||||||
|                 [ |  | ||||||
|                     'date'                  => isset($invoice_data['payment.date']) ? date('Y-m-d', strtotime($invoice_data['payment.date'])) : date('y-m-d'), |  | ||||||
|                     'transaction_reference' => $this->getString($invoice_data, 'payment.transaction_reference'), |  | ||||||
|                     'amount'                => $this->getFloat($invoice_data, 'payment.amount'), |  | ||||||
|                 ], |  | ||||||
|             ]; |  | ||||||
|         } elseif ($status === 'paid') { |  | ||||||
|             $transformed['payments'] = [ |  | ||||||
|                 [ |  | ||||||
|                     'date'                  => isset($invoice_data['payment.date']) ? date('Y-m-d', strtotime($invoice_data['payment.date'])) : date('y-m-d'), |  | ||||||
|                     'transaction_reference' => $this->getString($invoice_data, 'payment.transaction_reference'), |  | ||||||
|                     'amount'                => $this->getFloat($invoice_data, 'invoice.amount'), |  | ||||||
|                 ], |  | ||||||
|             ]; |  | ||||||
|         } elseif (isset($transformed['amount']) && isset($transformed['balance']) && ($transformed['amount'] != $transformed['balance'])) { |  | ||||||
|             $transformed['payments'] = [ |  | ||||||
|                 [ |  | ||||||
|                     'date'                  => isset($invoice_data['payment.date']) ? date('Y-m-d', strtotime($invoice_data['payment.date'])) : date('y-m-d'), |  | ||||||
|                     'transaction_reference' => $this->getString($invoice_data, 'payment.transaction_reference'), |  | ||||||
|                     'amount'                => $transformed['amount'] - $transformed['balance'], |  | ||||||
|                 ], |  | ||||||
|             ]; |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         $line_items = []; |  | ||||||
|         foreach ($line_items_data as $record) { |  | ||||||
|             $line_items[] = [ |  | ||||||
|                 'quantity'           => $this->getFloat($record, 'item.quantity'), |  | ||||||
|                 'cost'               => $this->getFloat($record, 'item.cost'), |  | ||||||
|                 'product_key'        => $this->getString($record, 'item.product_key'), |  | ||||||
|                 'notes'              => $this->getString($record, 'item.notes'), |  | ||||||
|                 'discount'           => $this->getFloat($record, 'item.discount'), |  | ||||||
|                 'is_amount_discount' => filter_var($this->getString($record, 'item.is_amount_discount'), FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE), |  | ||||||
|                 'tax_name1'          => $this->getString($record, 'item.tax_name1'), |  | ||||||
|                 'tax_rate1'          => $this->getFloat($record, 'item.tax_rate1'), |  | ||||||
|                 'tax_name2'          => $this->getString($record, 'item.tax_name2'), |  | ||||||
|                 'tax_rate2'          => $this->getFloat($record, 'item.tax_rate2'), |  | ||||||
|                 'tax_name3'          => $this->getString($record, 'item.tax_name3'), |  | ||||||
|                 'tax_rate3'          => $this->getFloat($record, 'item.tax_rate3'), |  | ||||||
|                 'custom_value1'      => $this->getString($record, 'item.custom_value1'), |  | ||||||
|                 'custom_value2'      => $this->getString($record, 'item.custom_value2'), |  | ||||||
|                 'custom_value3'      => $this->getString($record, 'item.custom_value3'), |  | ||||||
|                 'custom_value4'      => $this->getString($record, 'item.custom_value4'), |  | ||||||
|                 'type_id'            => $this->getInvoiceTypeId($record, 'item.type_id'), |  | ||||||
|             ]; |  | ||||||
|         } |  | ||||||
|         $transformed['line_items'] = $line_items; |  | ||||||
| 
 |  | ||||||
|         return $transformed; |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @ -1,65 +0,0 @@ | |||||||
| <?php |  | ||||||
| /** |  | ||||||
|  * client Ninja (https://clientninja.com). |  | ||||||
|  * |  | ||||||
|  * @link https://github.com/clientninja/clientninja source repository |  | ||||||
|  * |  | ||||||
|  * @copyright Copyright (c) 2022. client Ninja LLC (https://clientninja.com) |  | ||||||
|  * |  | ||||||
|  * @license https://www.elastic.co/licensing/elastic-license |  | ||||||
|  */ |  | ||||||
| 
 |  | ||||||
| namespace App\Import\Transformers\Csv; |  | ||||||
| 
 |  | ||||||
| use App\Import\ImportException; |  | ||||||
| use App\Import\Transformers\BaseTransformer; |  | ||||||
| 
 |  | ||||||
| /** |  | ||||||
|  * Class PaymentTransformer. |  | ||||||
|  */ |  | ||||||
| class PaymentTransformer extends BaseTransformer |  | ||||||
| { |  | ||||||
|     /** |  | ||||||
|      * @param $data |  | ||||||
|      * |  | ||||||
|      * @return array |  | ||||||
|      */ |  | ||||||
|     public function transform($data) |  | ||||||
|     { |  | ||||||
|         $client_id = |  | ||||||
|             $this->getClient($this->getString($data, 'payment.client_id'), $this->getString($data, 'payment.client_id')); |  | ||||||
| 
 |  | ||||||
|         if (empty($client_id)) { |  | ||||||
|             throw new ImportException('Could not find client.'); |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         $transformed = [ |  | ||||||
|             'company_id'            => $this->maps['company']->id, |  | ||||||
|             'number'                => $this->getString($data, 'payment.number'), |  | ||||||
|             'user_id'               => $this->getString($data, 'payment.user_id'), |  | ||||||
|             'amount'                => $this->getFloat($data, 'payment.amount'), |  | ||||||
|             'refunded'              => $this->getFloat($data, 'payment.refunded'), |  | ||||||
|             'applied'               => $this->getFloat($data, 'payment.applied'), |  | ||||||
|             'transaction_reference' => $this->getString($data, 'payment.transaction_reference '), |  | ||||||
|             'date'                  => $this->getString($data, 'payment.date'), |  | ||||||
|             'private_notes'         => $this->getString($data, 'payment.private_notes'), |  | ||||||
|             'custom_value1'         => $this->getString($data, 'payment.custom_value1'), |  | ||||||
|             'custom_value2'         => $this->getString($data, 'payment.custom_value2'), |  | ||||||
|             'custom_value3'         => $this->getString($data, 'payment.custom_value3'), |  | ||||||
|             'custom_value4'         => $this->getString($data, 'payment.custom_value4'), |  | ||||||
|             'client_id'             => $client_id, |  | ||||||
|         ]; |  | ||||||
| 
 |  | ||||||
|         if (isset($data['payment.invoice_number']) && |  | ||||||
|             $invoice_id = $this->getInvoiceId($data['payment.invoice_number'])) { |  | ||||||
|             $transformed['invoices'] = [ |  | ||||||
|                 [ |  | ||||||
|                     'invoice_id' => $invoice_id, |  | ||||||
|                     'amount'     => $transformed['amount'] ?? null, |  | ||||||
|                 ], |  | ||||||
|             ]; |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         return $transformed; |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @ -1,47 +0,0 @@ | |||||||
| <?php |  | ||||||
| /** |  | ||||||
|  * Invoice Ninja (https://invoiceninja.com). |  | ||||||
|  * |  | ||||||
|  * @link https://github.com/invoiceninja/invoiceninja source repository |  | ||||||
|  * |  | ||||||
|  * @copyright Copyright (c) 2022. Invoice Ninja LLC (https://invoiceninja.com) |  | ||||||
|  * |  | ||||||
|  * @license https://www.elastic.co/licensing/elastic-license |  | ||||||
|  */ |  | ||||||
| 
 |  | ||||||
| namespace App\Import\Transformers\Csv; |  | ||||||
| 
 |  | ||||||
| use App\Import\Transformers\BaseTransformer; |  | ||||||
| 
 |  | ||||||
| /** |  | ||||||
|  * Class ProductTransformer. |  | ||||||
|  */ |  | ||||||
| class ProductTransformer extends BaseTransformer |  | ||||||
| { |  | ||||||
|     /** |  | ||||||
|      * @param $data |  | ||||||
|      * |  | ||||||
|      * @return array |  | ||||||
|      */ |  | ||||||
|     public function transform($data) |  | ||||||
|     { |  | ||||||
|         return [ |  | ||||||
|             'company_id' => $this->maps['company']->id, |  | ||||||
|             'product_key' => $this->getString($data, 'product.product_key'), |  | ||||||
|             'notes' => $this->getString($data, 'product.notes'), |  | ||||||
|             'cost' => $this->getFloat($data, 'product.cost'), |  | ||||||
|             'price' => $this->getFloat($data, 'product.price'), |  | ||||||
|             'quantity' => $this->getFloat($data, 'product.quantity'), |  | ||||||
|             'tax_name1' => $this->getString($data, 'product.tax_name1'), |  | ||||||
|             'tax_rate1' => $this->getFloat($data, 'product.tax_rate1'), |  | ||||||
|             'tax_name2' => $this->getString($data, 'product.tax_name2'), |  | ||||||
|             'tax_rate2' => $this->getFloat($data, 'product.tax_rate2'), |  | ||||||
|             'tax_name3' => $this->getString($data, 'product.tax_name3'), |  | ||||||
|             'tax_rate3' => $this->getFloat($data, 'product.tax_rate3'), |  | ||||||
|             'custom_value1' => $this->getString($data, 'product.custom_value1'), |  | ||||||
|             'custom_value2' => $this->getString($data, 'product.custom_value2'), |  | ||||||
|             'custom_value3' => $this->getString($data, 'product.custom_value3'), |  | ||||||
|             'custom_value4' => $this->getString($data, 'product.custom_value4'), |  | ||||||
|         ]; |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @ -1,54 +0,0 @@ | |||||||
| <?php |  | ||||||
| 
 |  | ||||||
| namespace App\Import\Transformers\Csv; |  | ||||||
| 
 |  | ||||||
| use App\Import\ImportException; |  | ||||||
| use App\Import\Transformers\BaseTransformer; |  | ||||||
| 
 |  | ||||||
| /** |  | ||||||
|  * Class VendorTransformer. |  | ||||||
|  */ |  | ||||||
| class VendorTransformer extends BaseTransformer |  | ||||||
| { |  | ||||||
|     /** |  | ||||||
|      * @param $data |  | ||||||
|      * |  | ||||||
|      * @return array|bool |  | ||||||
|      */ |  | ||||||
|     public function transform($data) |  | ||||||
|     { |  | ||||||
|         if (isset($data->name) && $this->hasVendor($data->name)) { |  | ||||||
|             throw new ImportException('Vendor already exists'); |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         return [ |  | ||||||
|             'company_id' => $this->maps['company']->id, |  | ||||||
|             'name'            => $this->getString($data, 'vendor.name'), |  | ||||||
|             'phone'           => $this->getString($data, 'vendor.phone'), |  | ||||||
|             'id_number'       => $this->getString($data, 'vendor.id_number'), |  | ||||||
|             'vat_number'      => $this->getString($data, 'vendor.vat_number'), |  | ||||||
|             'website'         => $this->getString($data, 'vendor.website'), |  | ||||||
|             'currency_id'     => $this->getCurrencyByCode($data, 'vendor.currency_id'), |  | ||||||
|             'public_notes'    => $this->getString($data, 'vendor.public_notes'), |  | ||||||
|             'private_notes'   => $this->getString($data, 'vendor.private_notes'), |  | ||||||
|             'address1'        => $this->getString($data, 'vendor.address1'), |  | ||||||
|             'address2'        => $this->getString($data, 'vendor.address2'), |  | ||||||
|             'city'            => $this->getString($data, 'vendor.city'), |  | ||||||
|             'state'           => $this->getString($data, 'vendor.state'), |  | ||||||
|             'postal_code'     => $this->getString($data, 'vendor.postal_code'), |  | ||||||
|             'custom_value1'        => $this->getString($data, 'vendor.custom_value1'), |  | ||||||
|             'custom_value2'        => $this->getString($data, 'vendor.custom_value2'), |  | ||||||
|             'custom_value3'        => $this->getString($data, 'vendor.custom_value3'), |  | ||||||
|             'custom_value4'        => $this->getString($data, 'vendor.custom_value4'), |  | ||||||
|             'vendor_contacts' => [ |  | ||||||
|                 [ |  | ||||||
|                     'first_name' => $this->getString($data, 'vendor.first_name'), |  | ||||||
|                     'last_name'  => $this->getString($data, 'vendor.last_name'), |  | ||||||
|                     'email'      => $this->getString($data, 'vendor.email'), |  | ||||||
|                     'phone'      => $this->getString($data, 'vendor.phone'), |  | ||||||
|                 ], |  | ||||||
|             ], |  | ||||||
|             'country_id'      => isset($data['vendor.country_id']) ? $this->getCountryId($data['vendor.country_id']) : null, |  | ||||||
|         ]; |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @ -1,57 +0,0 @@ | |||||||
| <?php |  | ||||||
| /** |  | ||||||
|  * Invoice Ninja (https://clientninja.com). |  | ||||||
|  * |  | ||||||
|  * @link https://github.com/clientninja/clientninja source repository |  | ||||||
|  * |  | ||||||
|  * @copyright Copyright (c) 2022. client Ninja LLC (https://clientninja.com) |  | ||||||
|  * |  | ||||||
|  * @license https://www.elastic.co/licensing/elastic-license |  | ||||||
|  */ |  | ||||||
| 
 |  | ||||||
| namespace App\Import\Transformers\Freshbooks; |  | ||||||
| 
 |  | ||||||
| use App\Import\ImportException; |  | ||||||
| use App\Import\Transformers\BaseTransformer; |  | ||||||
| use Illuminate\Support\Str; |  | ||||||
| 
 |  | ||||||
| /** |  | ||||||
|  * Class ClientTransformer. |  | ||||||
|  */ |  | ||||||
| class ClientTransformer extends BaseTransformer |  | ||||||
| { |  | ||||||
|     /** |  | ||||||
|      * @param $data |  | ||||||
|      * |  | ||||||
|      * @return array|bool |  | ||||||
|      */ |  | ||||||
|     public function transform($data) |  | ||||||
|     { |  | ||||||
|         if (isset($data['Organization']) && $this->hasClient($data['Organization'])) { |  | ||||||
|             throw new ImportException('Client already exists'); |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         return [ |  | ||||||
|             'company_id'     => $this->maps['company']->id, |  | ||||||
|             'name'           => $this->getString($data, 'Organization'), |  | ||||||
|             'phone'     => $this->getString($data, 'Phone'), |  | ||||||
|             'address1'       => $this->getString($data, 'Street'), |  | ||||||
|             'city'           => $this->getString($data, 'City'), |  | ||||||
|             'state'          => $this->getString($data, 'Province/State'), |  | ||||||
|             'postal_code'    => $this->getString($data, 'Postal Code'), |  | ||||||
|             'country_id'     => isset($data['Country']) ? $this->getCountryId($data['Country']) : null, |  | ||||||
|             'private_notes'   => $this->getString($data, 'Notes'), |  | ||||||
|             'credit_balance' => 0, |  | ||||||
|             'settings'       => new \stdClass, |  | ||||||
|             'client_hash'    => Str::random(40), |  | ||||||
|             'contacts'       => [ |  | ||||||
|                 [ |  | ||||||
|                     'first_name'    => $this->getString($data, 'First Name'), |  | ||||||
|                     'last_name'     => $this->getString($data, 'Last Name'), |  | ||||||
|                     'email'         => $this->getString($data, 'Email'), |  | ||||||
|                     'phone'         => $this->getString($data, 'Phone'), |  | ||||||
|                 ], |  | ||||||
|             ], |  | ||||||
|         ]; |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @ -1,87 +0,0 @@ | |||||||
| <?php |  | ||||||
| /** |  | ||||||
|  * client Ninja (https://clientninja.com). |  | ||||||
|  * |  | ||||||
|  * @link https://github.com/clientninja/clientninja source repository |  | ||||||
|  * |  | ||||||
|  * @copyright Copyright (c) 2022. client Ninja LLC (https://clientninja.com) |  | ||||||
|  * |  | ||||||
|  * @license https://www.elastic.co/licensing/elastic-license |  | ||||||
|  */ |  | ||||||
| 
 |  | ||||||
| namespace App\Import\Transformers\Freshbooks; |  | ||||||
| 
 |  | ||||||
| use App\Import\ImportException; |  | ||||||
| use App\Import\Transformers\BaseTransformer; |  | ||||||
| use App\Models\Invoice; |  | ||||||
| use App\Utils\Number; |  | ||||||
| 
 |  | ||||||
| /** |  | ||||||
|  * Class InvoiceTransformer. |  | ||||||
|  */ |  | ||||||
| class InvoiceTransformer extends BaseTransformer |  | ||||||
| { |  | ||||||
|     /** |  | ||||||
|      * @param $line_items_data |  | ||||||
|      * |  | ||||||
|      * @return bool|array |  | ||||||
|      */ |  | ||||||
|     public function transform($line_items_data) |  | ||||||
|     { |  | ||||||
|         $invoice_data = reset($line_items_data); |  | ||||||
| 
 |  | ||||||
|         if ($this->hasInvoice($invoice_data['Invoice #'])) { |  | ||||||
|             throw new ImportException('Invoice number already exists'); |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         $invoiceStatusMap = [ |  | ||||||
|             'sent'  => Invoice::STATUS_SENT, |  | ||||||
|             'draft' => Invoice::STATUS_DRAFT, |  | ||||||
|         ]; |  | ||||||
| 
 |  | ||||||
|         $transformed = [ |  | ||||||
|             'company_id'  => $this->maps['company']->id, |  | ||||||
|             'client_id'   => $this->getClient($this->getString($invoice_data, 'Client Name'), null), |  | ||||||
|             'number'      => $this->getString($invoice_data, 'Invoice #'), |  | ||||||
|             'date'        => isset($invoice_data['Date Issued']) ? date('Y-m-d', strtotime($invoice_data['Date Issued'])) : null, |  | ||||||
|             'currency_id' => $this->getCurrencyByCode($invoice_data, 'Currency'), |  | ||||||
|             'amount'      => 0, |  | ||||||
|             'status_id'   => $invoiceStatusMap[$status = |  | ||||||
|                     strtolower($this->getString($invoice_data, 'Invoice Status'))] ?? Invoice::STATUS_SENT, |  | ||||||
|             // 'viewed'      => $status === 'viewed',
 |  | ||||||
|         ]; |  | ||||||
| 
 |  | ||||||
|         $line_items = []; |  | ||||||
|         foreach ($line_items_data as $record) { |  | ||||||
|             $line_items[] = [ |  | ||||||
|                 'product_key'        => $this->getString($record, 'Item Name'), |  | ||||||
|                 'notes'              => $this->getString($record, 'Item Description'), |  | ||||||
|                 'cost'               => $this->getFreshbookQuantityFloat($record, 'Rate'), |  | ||||||
|                 'quantity'           => $this->getFreshbookQuantityFloat($record, 'Quantity'), |  | ||||||
|                 'discount'           => $this->getFreshbookQuantityFloat($record, 'Discount Percentage'), |  | ||||||
|                 'is_amount_discount' => false, |  | ||||||
|                 'tax_name1'          => $this->getString($record, 'Tax 1 Type'), |  | ||||||
|                 'tax_rate1'          => $this->getFreshbookQuantityFloat($record, 'Tax 1 Amount'), |  | ||||||
|                 'tax_name2'          => $this->getString($record, 'Tax 2 Type'), |  | ||||||
|                 'tax_rate2'          => $this->getFreshbookQuantityFloat($record, 'Tax 2 Amount'), |  | ||||||
|             ]; |  | ||||||
|             $transformed['amount'] += $this->getFreshbookQuantityFloat($record, 'Line Total'); |  | ||||||
|         } |  | ||||||
|         $transformed['line_items'] = $line_items; |  | ||||||
| 
 |  | ||||||
|         if (! empty($invoice_data['Date Paid'])) { |  | ||||||
|             $transformed['payments'] = [[ |  | ||||||
|                 'date'   => date('Y-m-d', strtotime($invoice_data['Date Paid'])), |  | ||||||
|                 'amount' => $transformed['amount'], |  | ||||||
|             ]]; |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         return $transformed; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     /** @return float  */ |  | ||||||
|     public function getFreshbookQuantityFloat($data, $field) |  | ||||||
|     { |  | ||||||
|         return $data[$field]; |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @ -1,91 +0,0 @@ | |||||||
| <?php |  | ||||||
| /** |  | ||||||
|  * client Ninja (https://clientninja.com). |  | ||||||
|  * |  | ||||||
|  * @link https://github.com/clientninja/clientninja source repository |  | ||||||
|  * |  | ||||||
|  * @copyright Copyright (c) 2022. client Ninja LLC (https://clientninja.com) |  | ||||||
|  * |  | ||||||
|  * @license https://www.elastic.co/licensing/elastic-license |  | ||||||
|  */ |  | ||||||
| 
 |  | ||||||
| namespace App\Import\Transformers\Invoice2Go; |  | ||||||
| 
 |  | ||||||
| use App\Import\ImportException; |  | ||||||
| use App\Import\Transformers\BaseTransformer; |  | ||||||
| use App\Models\Invoice; |  | ||||||
| use Illuminate\Support\Str; |  | ||||||
| 
 |  | ||||||
| /** |  | ||||||
|  * Class InvoiceTransformer. |  | ||||||
|  */ |  | ||||||
| class InvoiceTransformer extends BaseTransformer |  | ||||||
| { |  | ||||||
|     /** |  | ||||||
|      * @param $line_items_data |  | ||||||
|      * |  | ||||||
|      * @return bool|array |  | ||||||
|      */ |  | ||||||
|     public function transform($invoice_data) |  | ||||||
|     { |  | ||||||
|         if ($this->hasInvoice($invoice_data['DocumentNumber'])) { |  | ||||||
|             throw new ImportException('Invoice number already exists'); |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         $invoiceStatusMap = [ |  | ||||||
|             'unsent' => Invoice::STATUS_DRAFT, |  | ||||||
|             'sent'   => Invoice::STATUS_SENT, |  | ||||||
|         ]; |  | ||||||
| 
 |  | ||||||
|         $transformed = [ |  | ||||||
|             'company_id'  => $this->maps['company']->id, |  | ||||||
|             'number'      => $this->getString($invoice_data, 'DocumentNumber'), |  | ||||||
|             'notes'       => $this->getString($invoice_data, 'Comment'), |  | ||||||
|             'date'        => isset($invoice_data['DocumentDate']) ? date('Y-m-d', strtotime($invoice_data['DocumentDate'])) : null, |  | ||||||
|             'currency_id' => $this->getCurrencyByCode($invoice_data, 'Currency'), |  | ||||||
|             'amount'      => 0, |  | ||||||
|             'status_id'   => $invoiceStatusMap[$status = |  | ||||||
|                     strtolower($this->getString($invoice_data, 'DocumentStatus'))] ?? Invoice::STATUS_SENT, |  | ||||||
|             // 'viewed'      => $status === 'viewed',
 |  | ||||||
|             'line_items'  => [ |  | ||||||
|                 [ |  | ||||||
|                     'amount'             => $amount = $this->getFloat($invoice_data, 'TotalAmount'), |  | ||||||
|                     'quantity'           => 1, |  | ||||||
|                     'discount'           => $this->getFloat($invoice_data, 'DiscountValue'), |  | ||||||
|                     'is_amount_discount' => false, |  | ||||||
|                 ], |  | ||||||
|             ], |  | ||||||
|         ]; |  | ||||||
| 
 |  | ||||||
|         $client_id = |  | ||||||
|             $this->getClient($this->getString($invoice_data, 'Name'), $this->getString($invoice_data, 'EmailRecipient')); |  | ||||||
| 
 |  | ||||||
|         if ($client_id) { |  | ||||||
|             $transformed['client_id'] = $client_id; |  | ||||||
|         } else { |  | ||||||
|             $transformed['client'] = [ |  | ||||||
|                 'name'              => $this->getString($invoice_data, 'Name'), |  | ||||||
|                 'address1'          => $this->getString($invoice_data, 'DocumentRecipientAddress'), |  | ||||||
|                 'shipping_address1' => $this->getString($invoice_data, 'ShipAddress'), |  | ||||||
|                 'credit_balance'    => 0, |  | ||||||
|                 'settings'          => new \stdClass, |  | ||||||
|                 'client_hash'       => Str::random(40), |  | ||||||
|                 'contacts'          => [ |  | ||||||
|                     [ |  | ||||||
|                         'email' => $this->getString($invoice_data, 'Email'), |  | ||||||
|                     ], |  | ||||||
|                 ], |  | ||||||
|             ]; |  | ||||||
|         } |  | ||||||
|         if (! empty($invoice_data['Date Paid'])) { |  | ||||||
|             $transformed['payments'] = [ |  | ||||||
|                 [ |  | ||||||
|                     'date'   => date('Y-m-d', strtotime($invoice_data['DatePaid'])), |  | ||||||
|                     'amount' => $this->getFloat($invoice_data, 'Payments'), |  | ||||||
|                 ], |  | ||||||
|             ]; |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         return $transformed; |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @ -1,46 +0,0 @@ | |||||||
| <?php |  | ||||||
| /** |  | ||||||
|  * Invoice Ninja (https://invoiceninja.com). |  | ||||||
|  * |  | ||||||
|  * @link https://github.com/invoiceninja/invoiceninja source repository |  | ||||||
|  * |  | ||||||
|  * @copyright Copyright (c) 2022. Invoice Ninja LLC (https://invoiceninja.com) |  | ||||||
|  * |  | ||||||
|  * @license https://www.elastic.co/licensing/elastic-license |  | ||||||
|  */ |  | ||||||
| 
 |  | ||||||
| namespace App\Import\Transformers; |  | ||||||
| 
 |  | ||||||
| /** |  | ||||||
|  * Class InvoiceItemTransformer. |  | ||||||
|  */ |  | ||||||
| class InvoiceItemTransformer extends BaseTransformer |  | ||||||
| { |  | ||||||
|     /** |  | ||||||
|      * @param $data |  | ||||||
|      * |  | ||||||
|      * @return bool|Item |  | ||||||
|      */ |  | ||||||
|     public function transform($data) |  | ||||||
|     { |  | ||||||
|         return [ |  | ||||||
|             'quantity' => $this->getFloat($data, 'item.quantity'), |  | ||||||
|             'cost' => $this->getFloat($data, 'item.cost'), |  | ||||||
|             'product_key' => $this->getString($data, 'item.product_key'), |  | ||||||
|             'notes' => $this->getString($data, 'item.notes'), |  | ||||||
|             'discount' => $this->getFloat($data, 'item.discount'), |  | ||||||
|             'is_amount_discount' => $this->getString($data, 'item.is_amount_discount'), |  | ||||||
|             'tax_name1' => $this->getString($data, 'item.tax_name1'), |  | ||||||
|             'tax_rate1' => $this->getFloat($data, 'item.tax_rate1'), |  | ||||||
|             'tax_name2' => $this->getString($data, 'item.tax_name2'), |  | ||||||
|             'tax_rate2' => $this->getFloat($data, 'item.tax_rate2'), |  | ||||||
|             'tax_name3' => $this->getString($data, 'item.tax_name3'), |  | ||||||
|             'tax_rate3' => $this->getFloat($data, 'item.tax_rate3'), |  | ||||||
|             'custom_value1' => $this->getString($data, 'item.custom_value1'), |  | ||||||
|             'custom_value2' => $this->getString($data, 'item.custom_value2'), |  | ||||||
|             'custom_value3' => $this->getString($data, 'item.custom_value3'), |  | ||||||
|             'custom_value4' => $this->getString($data, 'item.custom_value4'), |  | ||||||
|             'type_id' => $this->getInvoiceTypeId($data, 'item.type_id'), |  | ||||||
|         ]; |  | ||||||
|     } |  | ||||||
| } |  | ||||||
Some files were not shown because too many files have changed in this diff Show More
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user