mirror of
https://github.com/invoiceninja/invoiceninja.git
synced 2025-05-24 02:14:21 -04:00
Merge remote-tracking branch 'upstream/v5-develop' into 1314-subscriptions-v3
This commit is contained in:
commit
31942cb401
@ -13,5 +13,10 @@ namespace Illuminate\Contracts\Mail
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public function brevo_config(string $key)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -11,53 +11,54 @@
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use App\DataMapper\ClientRegistrationFields;
|
||||
use App\DataMapper\CompanySettings;
|
||||
use App\DataMapper\FeesAndLimits;
|
||||
use App\Events\Invoice\InvoiceWasCreated;
|
||||
use App\Events\RecurringInvoice\RecurringInvoiceWasCreated;
|
||||
use App\Factory\GroupSettingFactory;
|
||||
use App\Factory\InvoiceFactory;
|
||||
use App\Factory\InvoiceItemFactory;
|
||||
use App\Factory\RecurringInvoiceFactory;
|
||||
use App\Factory\SubscriptionFactory;
|
||||
use App\Helpers\Invoice\InvoiceSum;
|
||||
use App\Jobs\Company\CreateCompanyTaskStatuses;
|
||||
use App\Libraries\MultiDB;
|
||||
use App\Models\Account;
|
||||
use App\Models\BankIntegration;
|
||||
use App\Models\BankTransaction;
|
||||
use App\Models\BankTransactionRule;
|
||||
use stdClass;
|
||||
use Carbon\Carbon;
|
||||
use Faker\Factory;
|
||||
use App\Models\Task;
|
||||
use App\Models\User;
|
||||
use App\Utils\Ninja;
|
||||
use App\Models\Quote;
|
||||
use App\Models\Client;
|
||||
use App\Models\ClientContact;
|
||||
use App\Models\Company;
|
||||
use App\Models\CompanyGateway;
|
||||
use App\Models\CompanyToken;
|
||||
use App\Models\Country;
|
||||
use App\Models\Credit;
|
||||
use App\Models\Vendor;
|
||||
use App\Models\Account;
|
||||
use App\Models\Company;
|
||||
use App\Models\Country;
|
||||
use App\Models\Expense;
|
||||
use App\Models\Invoice;
|
||||
use App\Models\Product;
|
||||
use App\Models\Project;
|
||||
use App\Models\Quote;
|
||||
use App\Models\RecurringInvoice;
|
||||
use App\Models\Task;
|
||||
use App\Models\TaskStatus;
|
||||
use App\Models\TaxRate;
|
||||
use App\Models\User;
|
||||
use App\Models\Vendor;
|
||||
use App\Libraries\MultiDB;
|
||||
use App\Models\TaskStatus;
|
||||
use App\Models\CompanyToken;
|
||||
use App\Models\ClientContact;
|
||||
use App\Models\VendorContact;
|
||||
use App\Repositories\InvoiceRepository;
|
||||
use App\Utils\Ninja;
|
||||
use App\Utils\Traits\GeneratesCounter;
|
||||
use App\Models\CompanyGateway;
|
||||
use App\Factory\InvoiceFactory;
|
||||
use App\Models\BankIntegration;
|
||||
use App\Models\BankTransaction;
|
||||
use App\Utils\Traits\MakesHash;
|
||||
use Carbon\Carbon;
|
||||
use Faker\Factory;
|
||||
use Illuminate\Console\Command;
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
use App\Models\RecurringInvoice;
|
||||
use App\DataMapper\FeesAndLimits;
|
||||
use App\DataMapper\ClientSettings;
|
||||
use App\DataMapper\CompanySettings;
|
||||
use App\Factory\InvoiceItemFactory;
|
||||
use App\Helpers\Invoice\InvoiceSum;
|
||||
use App\Models\BankTransactionRule;
|
||||
use App\Factory\GroupSettingFactory;
|
||||
use App\Factory\SubscriptionFactory;
|
||||
use Illuminate\Support\Facades\Hash;
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
use App\Utils\Traits\GeneratesCounter;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use stdClass;
|
||||
use App\Repositories\InvoiceRepository;
|
||||
use App\Factory\RecurringInvoiceFactory;
|
||||
use App\Events\Invoice\InvoiceWasCreated;
|
||||
use App\DataMapper\ClientRegistrationFields;
|
||||
use App\Jobs\Company\CreateCompanyTaskStatuses;
|
||||
use App\Events\RecurringInvoice\RecurringInvoiceWasCreated;
|
||||
|
||||
class CreateSingleAccount extends Command
|
||||
{
|
||||
@ -951,7 +952,7 @@ class CreateSingleAccount extends Command
|
||||
}
|
||||
|
||||
|
||||
if (config('ninja.testvars.paytrace.decrypted') && ($this->gateway == 'all' || $this->gateway == 'paytrace')) {
|
||||
if (config('ninja.testvars.paytrace') && ($this->gateway == 'all' || $this->gateway == 'paytrace')) {
|
||||
$cg = new CompanyGateway();
|
||||
$cg->company_id = $company->id;
|
||||
$cg->user_id = $user->id;
|
||||
@ -960,7 +961,7 @@ class CreateSingleAccount extends Command
|
||||
$cg->require_billing_address = true;
|
||||
$cg->require_shipping_address = true;
|
||||
$cg->update_details = true;
|
||||
$cg->config = encrypt(config('ninja.testvars.paytrace.decrypted'));
|
||||
$cg->config = encrypt(config('ninja.testvars.paytrace'));
|
||||
|
||||
$cg->save();
|
||||
|
||||
@ -1015,6 +1016,85 @@ class CreateSingleAccount extends Command
|
||||
$cg->fees_and_limits = $fees_and_limits;
|
||||
$cg->save();
|
||||
}
|
||||
|
||||
if (config('ninja.testvars.eway') && ($this->gateway == 'all' || $this->gateway == 'eway')) {
|
||||
$cg = new CompanyGateway();
|
||||
$cg->company_id = $company->id;
|
||||
$cg->user_id = $user->id;
|
||||
$cg->gateway_key = '944c20175bbe6b9972c05bcfe294c2c7';
|
||||
$cg->require_cvv = true;
|
||||
$cg->require_billing_address = true;
|
||||
$cg->require_shipping_address = true;
|
||||
$cg->update_details = true;
|
||||
$cg->config = encrypt(config('ninja.testvars.eway'));
|
||||
$cg->save();
|
||||
|
||||
$gateway_types = $cg->driver()->gatewayTypes();
|
||||
|
||||
$fees_and_limits = new stdClass();
|
||||
$fees_and_limits->{$gateway_types[0]} = new FeesAndLimits();
|
||||
|
||||
$cg->fees_and_limits = $fees_and_limits;
|
||||
$cg->save();
|
||||
}
|
||||
|
||||
|
||||
if (config('ninja.testvars.gocardless') && ($this->gateway == 'all' || $this->gateway == 'gocardless')) {
|
||||
|
||||
$c_settings = ClientSettings::defaults();
|
||||
$c_settings->currency_id = '2';
|
||||
|
||||
$client = Client::factory()->create([
|
||||
'user_id' => $user->id,
|
||||
'company_id' => $company->id,
|
||||
'name' => 'cypress',
|
||||
'country_id' => 826,
|
||||
'settings' => $c_settings
|
||||
]);
|
||||
|
||||
$cg = new CompanyGateway();
|
||||
$cg->company_id = $company->id;
|
||||
$cg->user_id = $user->id;
|
||||
$cg->gateway_key = 'b9886f9257f0c6ee7c302f1c74475f6c';
|
||||
$cg->require_cvv = true;
|
||||
$cg->require_billing_address = true;
|
||||
$cg->require_shipping_address = true;
|
||||
$cg->update_details = true;
|
||||
$cg->config = encrypt(config('ninja.testvars.gocardless'));
|
||||
$cg->save();
|
||||
|
||||
$gateway_types = $cg->driver($client)->gatewayTypes();
|
||||
|
||||
$fees_and_limits = new stdClass();
|
||||
$fees_and_limits->{$gateway_types[0]} = new FeesAndLimits();
|
||||
|
||||
$cg->fees_and_limits = $fees_and_limits;
|
||||
$cg->save();
|
||||
}
|
||||
|
||||
if (config('ninja.testvars.forte') && ($this->gateway == 'all' || $this->gateway == 'forte')) {
|
||||
$cg = new CompanyGateway();
|
||||
$cg->company_id = $company->id;
|
||||
$cg->user_id = $user->id;
|
||||
$cg->gateway_key = 'kivcvjexxvdiyqtj3mju5d6yhpeht2xs';
|
||||
$cg->require_cvv = true;
|
||||
$cg->require_billing_address = true;
|
||||
$cg->require_shipping_address = true;
|
||||
$cg->update_details = true;
|
||||
$cg->config = encrypt(config('ninja.testvars.forte'));
|
||||
$cg->save();
|
||||
|
||||
$gateway_types = $cg->driver()->gatewayTypes();
|
||||
|
||||
$fees_and_limits = new stdClass();
|
||||
$fees_and_limits->{$gateway_types[0]} = new FeesAndLimits();
|
||||
|
||||
$cg->fees_and_limits = $fees_and_limits;
|
||||
$cg->save();
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
private function createRecurringInvoice(Client $client)
|
||||
|
@ -229,7 +229,7 @@ class CompanySettings extends BaseSettings
|
||||
public $require_quote_signature = false; //@TODO ben to confirm
|
||||
|
||||
//email settings
|
||||
public $email_sending_method = 'default'; //enum 'default','gmail','office365' 'client_postmark', 'client_mailgun', 'mailgun' //@implemented
|
||||
public $email_sending_method = 'default'; //enum 'default','gmail','office365' 'client_postmark', 'client_mailgun', 'mailgun', 'client_brevo' //@implemented
|
||||
|
||||
public $gmail_sending_user_id = '0'; //@implemented
|
||||
|
||||
@ -451,6 +451,8 @@ class CompanySettings extends BaseSettings
|
||||
|
||||
public $mailgun_endpoint = 'api.mailgun.net'; //api.eu.mailgun.net
|
||||
|
||||
public $brevo_secret = '';
|
||||
|
||||
public $auto_bill_standard_invoices = false;
|
||||
|
||||
public $email_alignment = 'center'; // center , left, right
|
||||
@ -477,6 +479,8 @@ class CompanySettings extends BaseSettings
|
||||
|
||||
public $e_invoice_type = 'EN16931';
|
||||
|
||||
public $e_quote_type = 'OrderX_Comfort';
|
||||
|
||||
public $default_expense_payment_type_id = '0';
|
||||
|
||||
public $enable_e_invoice = false;
|
||||
@ -497,7 +501,11 @@ class CompanySettings extends BaseSettings
|
||||
|
||||
public $use_unapplied_payment = 'off'; //always, option, off //@implemented
|
||||
|
||||
public $enable_rappen_rounding = false;
|
||||
|
||||
public static $casts = [
|
||||
'e_quote_type' => 'string',
|
||||
'enable_rappen_rounding' => 'bool',
|
||||
'use_unapplied_payment' => 'string',
|
||||
'show_pdfhtml_on_mobile' => 'bool',
|
||||
'payment_email_all_contacts' => 'bool',
|
||||
@ -517,262 +525,263 @@ class CompanySettings extends BaseSettings
|
||||
'show_task_item_description' => 'bool',
|
||||
'allow_billable_task_items' => 'bool',
|
||||
'accept_client_input_quote_approval' => 'bool',
|
||||
'custom_sending_email' => 'string',
|
||||
'show_paid_stamp' => 'bool',
|
||||
'show_shipping_address' => 'bool',
|
||||
'company_logo_size' => 'string',
|
||||
'show_email_footer' => 'bool',
|
||||
'email_alignment' => 'string',
|
||||
'auto_bill_standard_invoices' => 'bool',
|
||||
'postmark_secret' => 'string',
|
||||
'mailgun_secret' => 'string',
|
||||
'mailgun_domain' => 'string',
|
||||
'send_email_on_mark_paid' => 'bool',
|
||||
'vendor_portal_enable_uploads' => 'bool',
|
||||
'besr_id' => 'string',
|
||||
'qr_iban' => 'string',
|
||||
'email_subject_purchase_order' => 'string',
|
||||
'email_template_purchase_order' => 'string',
|
||||
'require_purchase_order_signature' => 'bool',
|
||||
'purchase_order_public_notes' => 'string',
|
||||
'purchase_order_terms' => 'string',
|
||||
'purchase_order_design_id' => 'string',
|
||||
'purchase_order_footer' => 'string',
|
||||
'purchase_order_number_pattern' => 'string',
|
||||
'page_numbering_alignment' => 'string',
|
||||
'page_numbering' => 'bool',
|
||||
'auto_archive_invoice_cancelled' => 'bool',
|
||||
'email_from_name' => 'string',
|
||||
'show_all_tasks_client_portal' => 'string',
|
||||
'entity_send_time' => 'int',
|
||||
'shared_invoice_credit_counter' => 'bool',
|
||||
'reply_to_name' => 'string',
|
||||
'hide_empty_columns_on_pdf' => 'bool',
|
||||
'enable_reminder_endless' => 'bool',
|
||||
'use_credits_payment' => 'string',
|
||||
'recurring_invoice_number_pattern' => 'string',
|
||||
'recurring_invoice_number_counter' => 'int',
|
||||
'custom_sending_email' => 'string',
|
||||
'show_paid_stamp' => 'bool',
|
||||
'show_shipping_address' => 'bool',
|
||||
'company_logo_size' => 'string',
|
||||
'show_email_footer' => 'bool',
|
||||
'email_alignment' => 'string',
|
||||
'auto_bill_standard_invoices' => 'bool',
|
||||
'postmark_secret' => 'string',
|
||||
'mailgun_secret' => 'string',
|
||||
'mailgun_domain' => 'string',
|
||||
'brevo_secret' => 'string',
|
||||
'send_email_on_mark_paid' => 'bool',
|
||||
'vendor_portal_enable_uploads' => 'bool',
|
||||
'besr_id' => 'string',
|
||||
'qr_iban' => 'string',
|
||||
'email_subject_purchase_order' => 'string',
|
||||
'email_template_purchase_order' => 'string',
|
||||
'require_purchase_order_signature' => 'bool',
|
||||
'purchase_order_public_notes' => 'string',
|
||||
'purchase_order_terms' => 'string',
|
||||
'purchase_order_design_id' => 'string',
|
||||
'purchase_order_footer' => 'string',
|
||||
'purchase_order_number_pattern' => 'string',
|
||||
'page_numbering_alignment' => 'string',
|
||||
'page_numbering' => 'bool',
|
||||
'auto_archive_invoice_cancelled' => 'bool',
|
||||
'email_from_name' => 'string',
|
||||
'show_all_tasks_client_portal' => 'string',
|
||||
'entity_send_time' => 'int',
|
||||
'shared_invoice_credit_counter' => 'bool',
|
||||
'reply_to_name' => 'string',
|
||||
'hide_empty_columns_on_pdf' => 'bool',
|
||||
'enable_reminder_endless' => 'bool',
|
||||
'use_credits_payment' => 'string',
|
||||
'recurring_invoice_number_pattern' => 'string',
|
||||
'recurring_invoice_number_counter' => 'int',
|
||||
'client_portal_under_payment_minimum' => 'float',
|
||||
'auto_bill_date' => 'string',
|
||||
'primary_color' => 'string',
|
||||
'secondary_color' => 'string',
|
||||
'client_portal_allow_under_payment' => 'bool',
|
||||
'client_portal_allow_over_payment' => 'bool',
|
||||
'auto_bill' => 'string',
|
||||
'lock_invoices' => 'string',
|
||||
'client_portal_terms' => 'string',
|
||||
'client_portal_privacy_policy' => 'string',
|
||||
'client_can_register' => 'bool',
|
||||
'portal_design_id' => 'string',
|
||||
'late_fee_endless_percent' => 'float',
|
||||
'late_fee_endless_amount' => 'float',
|
||||
'auto_email_invoice' => 'bool',
|
||||
'reminder_send_time' => 'int',
|
||||
'email_sending_method' => 'string',
|
||||
'gmail_sending_user_id' => 'string',
|
||||
'counter_number_applied' => 'string',
|
||||
'quote_number_applied' => 'string',
|
||||
'email_subject_custom1' => 'string',
|
||||
'email_subject_custom2' => 'string',
|
||||
'email_subject_custom3' => 'string',
|
||||
'email_template_custom1' => 'string',
|
||||
'email_template_custom2' => 'string',
|
||||
'email_template_custom3' => 'string',
|
||||
'enable_reminder1' => 'bool',
|
||||
'enable_reminder2' => 'bool',
|
||||
'enable_reminder3' => 'bool',
|
||||
'num_days_reminder1' => 'int',
|
||||
'num_days_reminder2' => 'int',
|
||||
'num_days_reminder3' => 'int',
|
||||
'schedule_reminder1' => 'string', // (enum: after_invoice_date, before_due_date, after_due_date)
|
||||
'schedule_reminder2' => 'string', // (enum: after_invoice_date, before_due_date, after_due_date)
|
||||
'schedule_reminder3' => 'string', // (enum: after_invoice_date, before_due_date, after_due_date)
|
||||
'late_fee_amount1' => 'float',
|
||||
'late_fee_amount2' => 'float',
|
||||
'late_fee_amount3' => 'float',
|
||||
'late_fee_percent1' => 'float',
|
||||
'late_fee_percent2' => 'float',
|
||||
'late_fee_percent3' => 'float',
|
||||
'endless_reminder_frequency_id' => 'integer',
|
||||
'auto_bill_date' => 'string',
|
||||
'primary_color' => 'string',
|
||||
'secondary_color' => 'string',
|
||||
'client_portal_allow_under_payment' => 'bool',
|
||||
'client_portal_allow_over_payment' => 'bool',
|
||||
'auto_bill' => 'string',
|
||||
'lock_invoices' => 'string',
|
||||
'client_portal_terms' => 'string',
|
||||
'client_portal_privacy_policy' => 'string',
|
||||
'client_can_register' => 'bool',
|
||||
'portal_design_id' => 'string',
|
||||
'late_fee_endless_percent' => 'float',
|
||||
'late_fee_endless_amount' => 'float',
|
||||
'auto_email_invoice' => 'bool',
|
||||
'reminder_send_time' => 'int',
|
||||
'email_sending_method' => 'string',
|
||||
'gmail_sending_user_id' => 'string',
|
||||
'counter_number_applied' => 'string',
|
||||
'quote_number_applied' => 'string',
|
||||
'email_subject_custom1' => 'string',
|
||||
'email_subject_custom2' => 'string',
|
||||
'email_subject_custom3' => 'string',
|
||||
'email_template_custom1' => 'string',
|
||||
'email_template_custom2' => 'string',
|
||||
'email_template_custom3' => 'string',
|
||||
'enable_reminder1' => 'bool',
|
||||
'enable_reminder2' => 'bool',
|
||||
'enable_reminder3' => 'bool',
|
||||
'num_days_reminder1' => 'int',
|
||||
'num_days_reminder2' => 'int',
|
||||
'num_days_reminder3' => 'int',
|
||||
'schedule_reminder1' => 'string', // (enum: after_invoice_date, before_due_date, after_due_date)
|
||||
'schedule_reminder2' => 'string', // (enum: after_invoice_date, before_due_date, after_due_date)
|
||||
'schedule_reminder3' => 'string', // (enum: after_invoice_date, before_due_date, after_due_date)
|
||||
'late_fee_amount1' => 'float',
|
||||
'late_fee_amount2' => 'float',
|
||||
'late_fee_amount3' => 'float',
|
||||
'late_fee_percent1' => 'float',
|
||||
'late_fee_percent2' => 'float',
|
||||
'late_fee_percent3' => 'float',
|
||||
'endless_reminder_frequency_id' => 'integer',
|
||||
'client_online_payment_notification' => 'bool',
|
||||
'client_manual_payment_notification' => 'bool',
|
||||
'document_email_attachment' => 'bool',
|
||||
'enable_client_portal_password' => 'bool',
|
||||
'enable_email_markup' => 'bool',
|
||||
'enable_client_portal_dashboard' => 'bool',
|
||||
'enable_client_portal' => 'bool',
|
||||
'email_template_statement' => 'string',
|
||||
'email_subject_statement' => 'string',
|
||||
'signature_on_pdf' => 'bool',
|
||||
'quote_footer' => 'string',
|
||||
'page_size' => 'string',
|
||||
'page_layout' => 'string',
|
||||
'font_size' => 'int',
|
||||
'primary_font' => 'string',
|
||||
'secondary_font' => 'string',
|
||||
'hide_paid_to_date' => 'bool',
|
||||
'embed_documents' => 'bool',
|
||||
'all_pages_header' => 'bool',
|
||||
'all_pages_footer' => 'bool',
|
||||
'project_number_pattern' => 'string',
|
||||
'project_number_counter' => 'int',
|
||||
'task_number_pattern' => 'string',
|
||||
'task_number_counter' => 'int',
|
||||
'expense_number_pattern' => 'string',
|
||||
'expense_number_counter' => 'int',
|
||||
'recurring_expense_number_pattern' => 'string',
|
||||
'recurring_expense_number_counter' => 'int',
|
||||
'recurring_quote_number_pattern' => 'string',
|
||||
'recurring_quote_number_counter' => 'int',
|
||||
'vendor_number_pattern' => 'string',
|
||||
'vendor_number_counter' => 'int',
|
||||
'ticket_number_pattern' => 'string',
|
||||
'ticket_number_counter' => 'int',
|
||||
'payment_number_pattern' => 'string',
|
||||
'payment_number_counter' => 'int',
|
||||
'reply_to_email' => 'string',
|
||||
'bcc_email' => 'string',
|
||||
'pdf_email_attachment' => 'bool',
|
||||
'ubl_email_attachment' => 'bool',
|
||||
'email_style' => 'string',
|
||||
'email_style_custom' => 'string',
|
||||
'company_gateway_ids' => 'string',
|
||||
'address1' => 'string',
|
||||
'address2' => 'string',
|
||||
'city' => 'string',
|
||||
'company_logo' => 'string',
|
||||
'country_id' => 'string',
|
||||
'client_number_pattern' => 'string',
|
||||
'client_number_counter' => 'integer',
|
||||
'credit_number_pattern' => 'string',
|
||||
'credit_number_counter' => 'integer',
|
||||
'currency_id' => 'string',
|
||||
'custom_value1' => 'string',
|
||||
'custom_value2' => 'string',
|
||||
'custom_value3' => 'string',
|
||||
'custom_value4' => 'string',
|
||||
'custom_message_dashboard' => 'string',
|
||||
'custom_message_unpaid_invoice' => 'string',
|
||||
'custom_message_paid_invoice' => 'string',
|
||||
'custom_message_unapproved_quote' => 'string',
|
||||
'default_task_rate' => 'float',
|
||||
'email_signature' => 'string',
|
||||
'email_subject_invoice' => 'string',
|
||||
'email_subject_quote' => 'string',
|
||||
'email_subject_credit' => 'string',
|
||||
'email_subject_payment' => 'string',
|
||||
'email_subject_payment_partial' => 'string',
|
||||
'email_template_invoice' => 'string',
|
||||
'email_template_quote' => 'string',
|
||||
'email_template_credit' => 'string',
|
||||
'email_template_payment' => 'string',
|
||||
'email_template_payment_partial' => 'string',
|
||||
'email_subject_reminder1' => 'string',
|
||||
'email_subject_reminder2' => 'string',
|
||||
'email_subject_reminder3' => 'string',
|
||||
'email_subject_reminder_endless' => 'string',
|
||||
'email_template_reminder1' => 'string',
|
||||
'email_template_reminder2' => 'string',
|
||||
'email_template_reminder3' => 'string',
|
||||
'email_template_reminder_endless' => 'string',
|
||||
'inclusive_taxes' => 'bool',
|
||||
'invoice_number_pattern' => 'string',
|
||||
'invoice_number_counter' => 'integer',
|
||||
'invoice_design_id' => 'string',
|
||||
'document_email_attachment' => 'bool',
|
||||
'enable_client_portal_password' => 'bool',
|
||||
'enable_email_markup' => 'bool',
|
||||
'enable_client_portal_dashboard' => 'bool',
|
||||
'enable_client_portal' => 'bool',
|
||||
'email_template_statement' => 'string',
|
||||
'email_subject_statement' => 'string',
|
||||
'signature_on_pdf' => 'bool',
|
||||
'quote_footer' => 'string',
|
||||
'page_size' => 'string',
|
||||
'page_layout' => 'string',
|
||||
'font_size' => 'int',
|
||||
'primary_font' => 'string',
|
||||
'secondary_font' => 'string',
|
||||
'hide_paid_to_date' => 'bool',
|
||||
'embed_documents' => 'bool',
|
||||
'all_pages_header' => 'bool',
|
||||
'all_pages_footer' => 'bool',
|
||||
'project_number_pattern' => 'string',
|
||||
'project_number_counter' => 'int',
|
||||
'task_number_pattern' => 'string',
|
||||
'task_number_counter' => 'int',
|
||||
'expense_number_pattern' => 'string',
|
||||
'expense_number_counter' => 'int',
|
||||
'recurring_expense_number_pattern' => 'string',
|
||||
'recurring_expense_number_counter' => 'int',
|
||||
'recurring_quote_number_pattern' => 'string',
|
||||
'recurring_quote_number_counter' => 'int',
|
||||
'vendor_number_pattern' => 'string',
|
||||
'vendor_number_counter' => 'int',
|
||||
'ticket_number_pattern' => 'string',
|
||||
'ticket_number_counter' => 'int',
|
||||
'payment_number_pattern' => 'string',
|
||||
'payment_number_counter' => 'int',
|
||||
'reply_to_email' => 'string',
|
||||
'bcc_email' => 'string',
|
||||
'pdf_email_attachment' => 'bool',
|
||||
'ubl_email_attachment' => 'bool',
|
||||
'email_style' => 'string',
|
||||
'email_style_custom' => 'string',
|
||||
'company_gateway_ids' => 'string',
|
||||
'address1' => 'string',
|
||||
'address2' => 'string',
|
||||
'city' => 'string',
|
||||
'company_logo' => 'string',
|
||||
'country_id' => 'string',
|
||||
'client_number_pattern' => 'string',
|
||||
'client_number_counter' => 'integer',
|
||||
'credit_number_pattern' => 'string',
|
||||
'credit_number_counter' => 'integer',
|
||||
'currency_id' => 'string',
|
||||
'custom_value1' => 'string',
|
||||
'custom_value2' => 'string',
|
||||
'custom_value3' => 'string',
|
||||
'custom_value4' => 'string',
|
||||
'custom_message_dashboard' => 'string',
|
||||
'custom_message_unpaid_invoice' => 'string',
|
||||
'custom_message_paid_invoice' => 'string',
|
||||
'custom_message_unapproved_quote' => 'string',
|
||||
'default_task_rate' => 'float',
|
||||
'email_signature' => 'string',
|
||||
'email_subject_invoice' => 'string',
|
||||
'email_subject_quote' => 'string',
|
||||
'email_subject_credit' => 'string',
|
||||
'email_subject_payment' => 'string',
|
||||
'email_subject_payment_partial' => 'string',
|
||||
'email_template_invoice' => 'string',
|
||||
'email_template_quote' => 'string',
|
||||
'email_template_credit' => 'string',
|
||||
'email_template_payment' => 'string',
|
||||
'email_template_payment_partial' => 'string',
|
||||
'email_subject_reminder1' => 'string',
|
||||
'email_subject_reminder2' => 'string',
|
||||
'email_subject_reminder3' => 'string',
|
||||
'email_subject_reminder_endless' => 'string',
|
||||
'email_template_reminder1' => 'string',
|
||||
'email_template_reminder2' => 'string',
|
||||
'email_template_reminder3' => 'string',
|
||||
'email_template_reminder_endless' => 'string',
|
||||
'inclusive_taxes' => 'bool',
|
||||
'invoice_number_pattern' => 'string',
|
||||
'invoice_number_counter' => 'integer',
|
||||
'invoice_design_id' => 'string',
|
||||
// 'invoice_fields' => 'string',
|
||||
'invoice_taxes' => 'int',
|
||||
'invoice_taxes' => 'int',
|
||||
//'enabled_item_tax_rates' => 'int',
|
||||
'invoice_footer' => 'string',
|
||||
'invoice_labels' => 'string',
|
||||
'invoice_terms' => 'string',
|
||||
'credit_footer' => 'string',
|
||||
'credit_terms' => 'string',
|
||||
'name' => 'string',
|
||||
'payment_terms' => 'string',
|
||||
'payment_type_id' => 'string',
|
||||
'phone' => 'string',
|
||||
'postal_code' => 'string',
|
||||
'quote_design_id' => 'string',
|
||||
'credit_design_id' => 'string',
|
||||
'quote_number_pattern' => 'string',
|
||||
'quote_number_counter' => 'integer',
|
||||
'quote_terms' => 'string',
|
||||
'recurring_number_prefix' => 'string',
|
||||
'reset_counter_frequency_id' => 'integer',
|
||||
'reset_counter_date' => 'string',
|
||||
'require_invoice_signature' => 'bool',
|
||||
'require_quote_signature' => 'bool',
|
||||
'state' => 'string',
|
||||
'email' => 'string',
|
||||
'vat_number' => 'string',
|
||||
'id_number' => 'string',
|
||||
'tax_name1' => 'string',
|
||||
'tax_name2' => 'string',
|
||||
'tax_name3' => 'string',
|
||||
'tax_rate1' => 'float',
|
||||
'tax_rate2' => 'float',
|
||||
'tax_rate3' => 'float',
|
||||
'show_accept_quote_terms' => 'bool',
|
||||
'show_accept_invoice_terms' => 'bool',
|
||||
'timezone_id' => 'string',
|
||||
'valid_until' => 'string',
|
||||
'date_format_id' => 'string',
|
||||
'military_time' => 'bool',
|
||||
'language_id' => 'string',
|
||||
'show_currency_code' => 'bool',
|
||||
'send_reminders' => 'bool',
|
||||
'enable_client_portal_tasks' => 'bool',
|
||||
'auto_archive_invoice' => 'bool',
|
||||
'auto_archive_quote' => 'bool',
|
||||
'auto_convert_quote' => 'bool',
|
||||
'shared_invoice_quote_counter' => 'bool',
|
||||
'counter_padding' => 'integer',
|
||||
'invoice_footer' => 'string',
|
||||
'invoice_labels' => 'string',
|
||||
'invoice_terms' => 'string',
|
||||
'credit_footer' => 'string',
|
||||
'credit_terms' => 'string',
|
||||
'name' => 'string',
|
||||
'payment_terms' => 'string',
|
||||
'payment_type_id' => 'string',
|
||||
'phone' => 'string',
|
||||
'postal_code' => 'string',
|
||||
'quote_design_id' => 'string',
|
||||
'credit_design_id' => 'string',
|
||||
'quote_number_pattern' => 'string',
|
||||
'quote_number_counter' => 'integer',
|
||||
'quote_terms' => 'string',
|
||||
'recurring_number_prefix' => 'string',
|
||||
'reset_counter_frequency_id' => 'integer',
|
||||
'reset_counter_date' => 'string',
|
||||
'require_invoice_signature' => 'bool',
|
||||
'require_quote_signature' => 'bool',
|
||||
'state' => 'string',
|
||||
'email' => 'string',
|
||||
'vat_number' => 'string',
|
||||
'id_number' => 'string',
|
||||
'tax_name1' => 'string',
|
||||
'tax_name2' => 'string',
|
||||
'tax_name3' => 'string',
|
||||
'tax_rate1' => 'float',
|
||||
'tax_rate2' => 'float',
|
||||
'tax_rate3' => 'float',
|
||||
'show_accept_quote_terms' => 'bool',
|
||||
'show_accept_invoice_terms' => 'bool',
|
||||
'timezone_id' => 'string',
|
||||
'valid_until' => 'string',
|
||||
'date_format_id' => 'string',
|
||||
'military_time' => 'bool',
|
||||
'language_id' => 'string',
|
||||
'show_currency_code' => 'bool',
|
||||
'send_reminders' => 'bool',
|
||||
'enable_client_portal_tasks' => 'bool',
|
||||
'auto_archive_invoice' => 'bool',
|
||||
'auto_archive_quote' => 'bool',
|
||||
'auto_convert_quote' => 'bool',
|
||||
'shared_invoice_quote_counter' => 'bool',
|
||||
'counter_padding' => 'integer',
|
||||
//'design' => 'string',
|
||||
'website' => 'string',
|
||||
'pdf_variables' => 'object',
|
||||
'portal_custom_head' => 'string',
|
||||
'portal_custom_css' => 'string',
|
||||
'portal_custom_footer' => 'string',
|
||||
'portal_custom_js' => 'string',
|
||||
'client_portal_enable_uploads' => 'bool',
|
||||
'purchase_order_number_counter' => 'integer',
|
||||
'website' => 'string',
|
||||
'pdf_variables' => 'object',
|
||||
'portal_custom_head' => 'string',
|
||||
'portal_custom_css' => 'string',
|
||||
'portal_custom_footer' => 'string',
|
||||
'portal_custom_js' => 'string',
|
||||
'client_portal_enable_uploads' => 'bool',
|
||||
'purchase_order_number_counter' => 'integer',
|
||||
];
|
||||
|
||||
public static $free_plan_casts = [
|
||||
'currency_id' => 'string',
|
||||
'company_gateway_ids' => 'string',
|
||||
'address1' => 'string',
|
||||
'address2' => 'string',
|
||||
'city' => 'string',
|
||||
'company_logo' => 'string',
|
||||
'country_id' => 'string',
|
||||
'custom_value1' => 'string',
|
||||
'custom_value2' => 'string',
|
||||
'custom_value3' => 'string',
|
||||
'custom_value4' => 'string',
|
||||
'inclusive_taxes' => 'bool',
|
||||
'name' => 'string',
|
||||
'payment_terms' => 'string',
|
||||
'payment_type_id' => 'string',
|
||||
'phone' => 'string',
|
||||
'postal_code' => 'string',
|
||||
'state' => 'string',
|
||||
'email' => 'string',
|
||||
'vat_number' => 'string',
|
||||
'id_number' => 'string',
|
||||
'tax_name1' => 'string',
|
||||
'tax_name2' => 'string',
|
||||
'tax_name3' => 'string',
|
||||
'tax_rate1' => 'float',
|
||||
'tax_rate2' => 'float',
|
||||
'tax_rate3' => 'float',
|
||||
'timezone_id' => 'string',
|
||||
'date_format_id' => 'string',
|
||||
'military_time' => 'bool',
|
||||
'language_id' => 'string',
|
||||
'show_currency_code' => 'bool',
|
||||
'website' => 'string',
|
||||
'default_task_rate' => 'float',
|
||||
'currency_id' => 'string',
|
||||
'company_gateway_ids' => 'string',
|
||||
'address1' => 'string',
|
||||
'address2' => 'string',
|
||||
'city' => 'string',
|
||||
'company_logo' => 'string',
|
||||
'country_id' => 'string',
|
||||
'custom_value1' => 'string',
|
||||
'custom_value2' => 'string',
|
||||
'custom_value3' => 'string',
|
||||
'custom_value4' => 'string',
|
||||
'inclusive_taxes' => 'bool',
|
||||
'name' => 'string',
|
||||
'payment_terms' => 'string',
|
||||
'payment_type_id' => 'string',
|
||||
'phone' => 'string',
|
||||
'postal_code' => 'string',
|
||||
'state' => 'string',
|
||||
'email' => 'string',
|
||||
'vat_number' => 'string',
|
||||
'id_number' => 'string',
|
||||
'tax_name1' => 'string',
|
||||
'tax_name2' => 'string',
|
||||
'tax_name3' => 'string',
|
||||
'tax_rate1' => 'float',
|
||||
'tax_rate2' => 'float',
|
||||
'tax_rate3' => 'float',
|
||||
'timezone_id' => 'string',
|
||||
'date_format_id' => 'string',
|
||||
'military_time' => 'bool',
|
||||
'language_id' => 'string',
|
||||
'show_currency_code' => 'bool',
|
||||
'website' => 'string',
|
||||
'default_task_rate' => 'float',
|
||||
];
|
||||
|
||||
/**
|
||||
@ -848,7 +857,7 @@ class CompanySettings extends BaseSettings
|
||||
$company_settings = (object) get_class_vars(self::class);
|
||||
|
||||
foreach ($company_settings as $key => $value) {
|
||||
if (! property_exists($settings, $key)) {
|
||||
if (!property_exists($settings, $key)) {
|
||||
$settings->{$key} = self::castAttribute($key, $company_settings->{$key});
|
||||
}
|
||||
}
|
||||
@ -881,7 +890,7 @@ class CompanySettings extends BaseSettings
|
||||
{
|
||||
$notification = new stdClass();
|
||||
$notification->email = [];
|
||||
$notification->email = ['invoice_sent_all','payment_success_all','payment_manual_all'];
|
||||
$notification->email = ['invoice_sent_all', 'payment_success_all', 'payment_manual_all'];
|
||||
|
||||
return $notification;
|
||||
}
|
||||
|
@ -213,7 +213,7 @@ class SettingsData
|
||||
|
||||
public bool $show_accept_quote_terms = false; //@TODO ben to confirm
|
||||
|
||||
public string $email_sending_method = 'default'; // enum 'default', 'gmail', 'office365', 'client_postmark', 'client_mailgun' //@implemented
|
||||
public string $email_sending_method = 'default'; // enum 'default', 'gmail', 'office365', 'client_postmark', 'client_mailgun' , 'client_brevo' //@implemented
|
||||
|
||||
public string $gmail_sending_user_id = '0'; //@implemented
|
||||
|
||||
@ -433,6 +433,8 @@ class SettingsData
|
||||
|
||||
public string $mailgun_endpoint = 'api.mailgun.net'; // api.eu.mailgun.net
|
||||
|
||||
public string $brevo_secret = '';
|
||||
|
||||
public bool $auto_bill_standard_invoices = false;
|
||||
|
||||
public string $email_alignment = 'center'; // center, left, right
|
||||
@ -469,8 +471,8 @@ class SettingsData
|
||||
|
||||
public function cast(mixed $object)
|
||||
{
|
||||
if(is_array($object)) {
|
||||
$object = (object)$object;
|
||||
if (is_array($object)) {
|
||||
$object = (object) $object;
|
||||
}
|
||||
|
||||
if (is_object($object)) {
|
||||
@ -478,9 +480,9 @@ class SettingsData
|
||||
|
||||
try {
|
||||
settype($object->{$key}, gettype($this->{$key}));
|
||||
} catch(\Exception | \Error | \Throwable $e) {
|
||||
} catch (\Exception | \Error | \Throwable $e) {
|
||||
|
||||
if(property_exists($this, $key)) {
|
||||
if (property_exists($this, $key)) {
|
||||
$object->{$key} = $this->{$key};
|
||||
} else {
|
||||
unset($object->{$key});
|
||||
@ -506,11 +508,11 @@ class SettingsData
|
||||
|
||||
public function toObject(): object
|
||||
{
|
||||
return (object)$this->object;
|
||||
return (object) $this->object;
|
||||
}
|
||||
|
||||
public function toArray(): array
|
||||
{
|
||||
return (array)$this->object;
|
||||
return (array) $this->object;
|
||||
}
|
||||
}
|
||||
|
88398
app/DataProviders/SMSNumbers.php
Normal file
88398
app/DataProviders/SMSNumbers.php
Normal file
File diff suppressed because it is too large
Load Diff
@ -294,6 +294,7 @@ class BaseExport
|
||||
'line_total' => 'item.line_total',
|
||||
'gross_line_total' => 'item.gross_line_total',
|
||||
'tax_amount' => 'item.tax_amount',
|
||||
'product_cost' => 'item.product_cost'
|
||||
];
|
||||
|
||||
protected array $quote_report_keys = [
|
||||
@ -426,8 +427,11 @@ class BaseExport
|
||||
|
||||
protected array $task_report_keys = [
|
||||
'start_date' => 'task.start_date',
|
||||
'start_time' => 'task.start_time',
|
||||
'end_date' => 'task.end_date',
|
||||
'end_time' => 'task.end_time',
|
||||
'duration' => 'task.duration',
|
||||
'duration_words' => 'task.duration_words',
|
||||
'rate' => 'task.rate',
|
||||
'number' => 'task.number',
|
||||
'description' => 'task.description',
|
||||
|
@ -11,18 +11,19 @@
|
||||
|
||||
namespace App\Export\CSV;
|
||||
|
||||
use App\Export\Decorators\Decorator;
|
||||
use App\Libraries\MultiDB;
|
||||
use App\Models\Company;
|
||||
use App\Models\DateFormat;
|
||||
use App\Models\Task;
|
||||
use App\Models\Timezone;
|
||||
use App\Transformers\TaskTransformer;
|
||||
use App\Utils\Ninja;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use League\Csv\Writer;
|
||||
use App\Models\Company;
|
||||
use App\Models\Timezone;
|
||||
use App\Libraries\MultiDB;
|
||||
use App\Models\DateFormat;
|
||||
use Carbon\CarbonInterval;
|
||||
use Illuminate\Support\Carbon;
|
||||
use Illuminate\Support\Facades\App;
|
||||
use League\Csv\Writer;
|
||||
use App\Export\Decorators\Decorator;
|
||||
use App\Transformers\TaskTransformer;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
|
||||
class TaskExport extends BaseExport
|
||||
{
|
||||
@ -177,19 +178,26 @@ class TaskExport extends BaseExport
|
||||
|
||||
foreach ($logs as $key => $item) {
|
||||
if (in_array('task.start_date', $this->input['report_keys']) || in_array('start_date', $this->input['report_keys'])) {
|
||||
$entity['task.start_date'] = Carbon::createFromTimeStamp($item[0])->setTimezone($timezone_name)->format($date_format_default);
|
||||
$carbon_object = Carbon::createFromTimeStamp($item[0])->setTimezone($timezone_name);
|
||||
$entity['task.start_date'] = $carbon_object->format($date_format_default);
|
||||
$entity['task.start_time'] = $carbon_object->format('H:i:s');
|
||||
}
|
||||
|
||||
if ((in_array('task.end_date', $this->input['report_keys']) || in_array('end_date', $this->input['report_keys'])) && $item[1] > 0) {
|
||||
$entity['task.end_date'] = Carbon::createFromTimeStamp($item[1])->setTimezone($timezone_name)->format($date_format_default);
|
||||
$carbon_object = Carbon::createFromTimeStamp($item[1])->setTimezone($timezone_name);
|
||||
$entity['task.end_date'] = $carbon_object->format($date_format_default);
|
||||
$entity['task.end_time'] = $carbon_object->format('H:i:s');
|
||||
}
|
||||
|
||||
if ((in_array('task.end_date', $this->input['report_keys']) || in_array('end_date', $this->input['report_keys'])) && $item[1] == 0) {
|
||||
$entity['task.end_date'] = ctrans('texts.is_running');
|
||||
$entity['task.end_time'] = ctrans('texts.is_running');
|
||||
}
|
||||
|
||||
if (in_array('task.duration', $this->input['report_keys']) || in_array('duration', $this->input['report_keys'])) {
|
||||
$entity['task.duration'] = $task->calcDuration();
|
||||
$seconds = $task->calcDuration();
|
||||
$entity['task.duration'] = $seconds;
|
||||
$entity['task.duration_words'] = CarbonInterval::seconds($seconds)->locale($this->company->locale())->cascade()->forHumans();
|
||||
}
|
||||
|
||||
$entity = $this->decorateAdvancedFields($task, $entity);
|
||||
@ -197,8 +205,12 @@ class TaskExport extends BaseExport
|
||||
$this->storage_array[] = $entity;
|
||||
|
||||
$entity['task.start_date'] = '';
|
||||
$entity['task.start_time'] = '';
|
||||
$entity['task.end_date'] = '';
|
||||
$entity['task.end_time'] = '';
|
||||
$entity['task.duration'] = '';
|
||||
$entity['task.duration_words'] = '';
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -23,7 +23,7 @@ class InvoiceDecorator extends Decorator implements DecoratorInterface
|
||||
$invoice = $entity;
|
||||
} elseif($entity->invoice) {
|
||||
$invoice = $entity->invoice;
|
||||
} elseif($entity->invoices()->exists()) {
|
||||
} elseif(method_exists($entity, 'invoices') && $entity->invoices()->exists()) {
|
||||
$invoice = $entity->invoices()->first();
|
||||
}
|
||||
|
||||
|
@ -58,7 +58,10 @@ class DesignFilters extends QueryFilters
|
||||
|
||||
public function entities(string $entities = ''): Builder
|
||||
{
|
||||
|
||||
|
||||
if(stripos($entities, 'statement') !== false)
|
||||
$entities = 'client';
|
||||
|
||||
if (strlen($entities) == 0 || str_contains($entities, ',')) {
|
||||
return $this->builder;
|
||||
}
|
||||
|
@ -200,14 +200,16 @@ class InvoiceFilters extends QueryFilters
|
||||
*/
|
||||
public function payable(string $client_id = ''): Builder
|
||||
{
|
||||
|
||||
if (strlen($client_id) == 0) {
|
||||
return $this->builder;
|
||||
}
|
||||
|
||||
return $this->builder->whereIn('status_id', [Invoice::STATUS_DRAFT, Invoice::STATUS_SENT, Invoice::STATUS_PARTIAL])
|
||||
->where('balance', '>', 0)
|
||||
->where('is_deleted', 0)
|
||||
->where('client_id', $this->decodePrimaryKey($client_id));
|
||||
return $this->builder
|
||||
->where('client_id', $this->decodePrimaryKey($client_id))
|
||||
->whereIn('status_id', [Invoice::STATUS_DRAFT, Invoice::STATUS_SENT, Invoice::STATUS_PARTIAL])
|
||||
->where('is_deleted', 0)
|
||||
->where('balance', '>', 0);
|
||||
}
|
||||
|
||||
|
||||
@ -329,7 +331,9 @@ class InvoiceFilters extends QueryFilters
|
||||
|
||||
if($sort_col[0] == 'number') {
|
||||
// return $this->builder->orderByRaw('CAST(number AS UNSIGNED), number ' . $dir);
|
||||
return $this->builder->orderByRaw('ABS(number) ' . $dir);
|
||||
// return $this->builder->orderByRaw("number REGEXP '^[A-Za-z]+$',CAST(number as SIGNED INTEGER),CAST(REPLACE(number,'-','')AS SIGNED INTEGER) ,number");
|
||||
// return $this->builder->orderByRaw('ABS(number) ' . $dir);
|
||||
return $this->builder->orderByRaw("REGEXP_REPLACE(number,'[^0-9]+','')+0 " . $dir);
|
||||
}
|
||||
|
||||
return $this->builder->orderBy($sort_col[0], $dir);
|
||||
|
@ -52,6 +52,7 @@ class InvoiceSum
|
||||
|
||||
public InvoiceItemSum $invoice_items;
|
||||
|
||||
private $rappen_rounding = false;
|
||||
/**
|
||||
* Constructs the object with Invoice and Settings object.
|
||||
*
|
||||
@ -63,8 +64,11 @@ class InvoiceSum
|
||||
|
||||
if ($this->invoice->client) {
|
||||
$this->precision = $this->invoice->client->currency()->precision;
|
||||
$this->rappen_rounding = $this->invoice->client->getSetting('enable_rappen_rounding');
|
||||
} else {
|
||||
$this->precision = $this->invoice->vendor->currency()->precision;
|
||||
$this->rappen_rounding = $this->invoice->vendor->getSetting('enable_rappen_rounding');
|
||||
|
||||
}
|
||||
|
||||
$this->tax_map = new Collection();
|
||||
@ -242,8 +246,6 @@ class InvoiceSum
|
||||
|
||||
if ($this->invoice->status_id != Invoice::STATUS_DRAFT) {
|
||||
if ($this->invoice->amount != $this->invoice->balance) {
|
||||
// $paid_to_date = $this->invoice->amount - $this->invoice->balance;
|
||||
|
||||
$this->invoice->balance = Number::roundValue($this->getTotal(), $this->precision) - $this->invoice->paid_to_date; //21-02-2024 cannot use the calculated $paid_to_date here as it could send the balance backward.
|
||||
} else {
|
||||
$this->invoice->balance = Number::roundValue($this->getTotal(), $this->precision);
|
||||
@ -252,11 +254,22 @@ class InvoiceSum
|
||||
/* Set new calculated total */
|
||||
$this->invoice->amount = $this->formatValue($this->getTotal(), $this->precision);
|
||||
|
||||
if($this->rappen_rounding){
|
||||
$this->invoice->amount = $this->roundRappen($this->invoice->amount);
|
||||
$this->invoice->balance = $this->roundRappen($this->invoice->balance);
|
||||
}
|
||||
|
||||
$this->invoice->total_taxes = $this->getTotalTaxes();
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
function roundRappen($value): float
|
||||
{
|
||||
return round($value / .05, 0) * .05;
|
||||
}
|
||||
|
||||
public function getSubTotal()
|
||||
{
|
||||
return $this->sub_total;
|
||||
|
@ -47,6 +47,8 @@ class InvoiceSumInclusive
|
||||
|
||||
private $precision;
|
||||
|
||||
private $rappen_rounding = false;
|
||||
|
||||
public InvoiceItemSumInclusive $invoice_items;
|
||||
/**
|
||||
* Constructs the object with Invoice and Settings object.
|
||||
@ -59,8 +61,10 @@ class InvoiceSumInclusive
|
||||
|
||||
if ($this->invoice->client) {
|
||||
$this->precision = $this->invoice->client->currency()->precision;
|
||||
$this->rappen_rounding = $this->invoice->client->getSetting('enable_rappen_rounding');
|
||||
} else {
|
||||
$this->precision = $this->invoice->vendor->currency()->precision;
|
||||
$this->rappen_rounding = $this->invoice->vendor->getSetting('enable_rappen_rounding');
|
||||
}
|
||||
|
||||
$this->tax_map = new Collection();
|
||||
@ -270,10 +274,20 @@ class InvoiceSumInclusive
|
||||
/* Set new calculated total */
|
||||
$this->invoice->amount = $this->formatValue($this->getTotal(), $this->precision);
|
||||
|
||||
if($this->rappen_rounding) {
|
||||
$this->invoice->amount = $this->roundRappen($this->invoice->amount);
|
||||
$this->invoice->balance = $this->roundRappen($this->invoice->balance);
|
||||
}
|
||||
|
||||
$this->invoice->total_taxes = $this->getTotalTaxes();
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
function roundRappen($value): float
|
||||
{
|
||||
return round($value / .05, 0) * .05;
|
||||
}
|
||||
|
||||
public function getSubTotal()
|
||||
{
|
||||
|
@ -43,7 +43,7 @@ class ContactLoginController extends Controller
|
||||
|
||||
if ($request->session()->has('company_key')) {
|
||||
MultiDB::findAndSetDbByCompanyKey($request->session()->get('company_key'));
|
||||
$company = Company::where('company_key', $request->input('company_key'))->first();
|
||||
$company = Company::where('company_key', $request->session()->get('company_key'))->first();
|
||||
} elseif ($request->has('company_key')) {
|
||||
MultiDB::findAndSetDbByCompanyKey($request->input('company_key'));
|
||||
$company = Company::where('company_key', $request->input('company_key'))->first();
|
||||
|
@ -390,13 +390,20 @@ class LoginController extends BaseController
|
||||
$truth->setUser($user);
|
||||
$truth->setCompany($set_company);
|
||||
|
||||
$user->account->companies->each(function ($company) use ($user) {
|
||||
if ($company->tokens()->where('is_system', true)->count() == 0) {
|
||||
(new CreateCompanyToken($company, $user, request()->server('HTTP_USER_AGENT')))->handle();
|
||||
//21-03-2024
|
||||
$cu->each(function ($cu){
|
||||
if(CompanyToken::where('company_id', $cu->company_id)->where('user_id', $cu->user_id)->where('is_system', true)->doesntExist()){
|
||||
(new CreateCompanyToken($cu->company, $cu->user, request()->server('HTTP_USER_AGENT')))->handle();
|
||||
}
|
||||
});
|
||||
|
||||
$truth->setCompanyToken(CompanyToken::where('user_id', $user->id)->where('company_id', $set_company->id)->first());
|
||||
// $user->account->companies->each(function ($company) use ($user) {
|
||||
// if ($company->tokens()->where('user_id',$user->id)->where('is_system', true)->count() == 0) {
|
||||
// (new CreateCompanyToken($company, $user, request()->server('HTTP_USER_AGENT')))->handle();
|
||||
// }
|
||||
// });
|
||||
|
||||
$truth->setCompanyToken(CompanyToken::where('user_id', $user->id)->where('company_id', $set_company->id)->where('is_system', true)->first());
|
||||
|
||||
return CompanyUser::query()->where('user_id', $user->id);
|
||||
}
|
||||
|
@ -90,14 +90,13 @@ class YodleeController extends BaseController
|
||||
$bank_integration->balance = $account['current_balance'];
|
||||
$bank_integration->currency = $account['account_currency'];
|
||||
$bank_integration->from_date = now()->subYear();
|
||||
|
||||
$bank_integration->integration_type = BankIntegration::INTEGRATION_TYPE_YODLEE;
|
||||
$bank_integration->auto_sync = true;
|
||||
|
||||
$bank_integration->save();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
$company->account->bank_integrations->where("integration_type", BankIntegration::INTEGRATION_TYPE_YODLEE)->where('auto_sync', true)->each(function ($bank_integration) use ($company) { // TODO: filter to yodlee only
|
||||
ProcessBankTransactionsYodlee::dispatch($company->account->id, $bank_integration);
|
||||
});
|
||||
|
72
app/Http/Controllers/BrevoController.php
Normal file
72
app/Http/Controllers/BrevoController.php
Normal file
@ -0,0 +1,72 @@
|
||||
<?php
|
||||
/**
|
||||
* Invoice Ninja (https://invoiceninja.com).
|
||||
*
|
||||
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||
*
|
||||
* @copyright Copyright (c) 2023. Invoice Ninja LLC (https://invoiceninja.com)
|
||||
*
|
||||
* @license https://www.elastic.co/licensing/elastic-license
|
||||
*/
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Jobs\Brevo\ProcessBrevoWebhook;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
/**
|
||||
* Class PostMarkController.
|
||||
*/
|
||||
class BrevoController extends BaseController
|
||||
{
|
||||
private $invitation;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Process Postmark Webhook.
|
||||
*
|
||||
*
|
||||
* @OA\Post(
|
||||
* path="/api/v1/postmark_webhook",
|
||||
* operationId="postmarkWebhook",
|
||||
* tags={"postmark"},
|
||||
* summary="Processing webhooks from PostMark",
|
||||
* description="Adds an credit to the system",
|
||||
* @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 credit 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/Credit"),
|
||||
* ),
|
||||
* @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 webhook(Request $request)
|
||||
{
|
||||
if ($request->has('token') && $request->get('token') == config('services.brevo.key')) {
|
||||
ProcessBrevoWebhook::dispatch($request->all())->delay(10);
|
||||
|
||||
return response()->json(['message' => 'Success'], 200);
|
||||
}
|
||||
|
||||
return response()->json(['message' => 'Unauthorized'], 403);
|
||||
}
|
||||
}
|
@ -11,26 +11,29 @@
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Models\Client;
|
||||
use App\Libraries\MultiDB;
|
||||
use Illuminate\Http\Response;
|
||||
use App\Models\CompanyGateway;
|
||||
use App\Utils\Traits\MakesHash;
|
||||
use App\DataMapper\FeesAndLimits;
|
||||
use App\Jobs\Util\ApplePayDomain;
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
use App\Factory\CompanyGatewayFactory;
|
||||
use App\Filters\CompanyGatewayFilters;
|
||||
use App\Repositories\CompanyRepository;
|
||||
use Illuminate\Foundation\Bus\DispatchesJobs;
|
||||
use App\Transformers\CompanyGatewayTransformer;
|
||||
use App\PaymentDrivers\Stripe\Jobs\StripeWebhook;
|
||||
use App\PaymentDrivers\CheckoutCom\CheckoutSetupWebhook;
|
||||
use App\Http\Requests\CompanyGateway\BulkCompanyGatewayRequest;
|
||||
use App\Http\Requests\CompanyGateway\CreateCompanyGatewayRequest;
|
||||
use App\Http\Requests\CompanyGateway\DestroyCompanyGatewayRequest;
|
||||
use App\Http\Requests\CompanyGateway\EditCompanyGatewayRequest;
|
||||
use App\Http\Requests\CompanyGateway\ShowCompanyGatewayRequest;
|
||||
use App\Http\Requests\CompanyGateway\TestCompanyGatewayRequest;
|
||||
use App\Http\Requests\CompanyGateway\StoreCompanyGatewayRequest;
|
||||
use App\Http\Requests\CompanyGateway\CreateCompanyGatewayRequest;
|
||||
use App\Http\Requests\CompanyGateway\UpdateCompanyGatewayRequest;
|
||||
use App\Jobs\Util\ApplePayDomain;
|
||||
use App\Models\Client;
|
||||
use App\Models\CompanyGateway;
|
||||
use App\PaymentDrivers\CheckoutCom\CheckoutSetupWebhook;
|
||||
use App\PaymentDrivers\Stripe\Jobs\StripeWebhook;
|
||||
use App\Repositories\CompanyRepository;
|
||||
use App\Transformers\CompanyGatewayTransformer;
|
||||
use App\Utils\Traits\MakesHash;
|
||||
use Illuminate\Foundation\Bus\DispatchesJobs;
|
||||
use Illuminate\Http\Response;
|
||||
use App\Http\Requests\CompanyGateway\DestroyCompanyGatewayRequest;
|
||||
|
||||
/**
|
||||
* Class CompanyGatewayController.
|
||||
@ -52,6 +55,9 @@ class CompanyGatewayController extends BaseController
|
||||
|
||||
private string $checkout_key = '3758e7f7c6f4cecf0f4f348b9a00f456';
|
||||
|
||||
private string $forte_key = 'kivcvjexxvdiyqtj3mju5d6yhpeht2xs';
|
||||
|
||||
|
||||
/**
|
||||
* CompanyGatewayController constructor.
|
||||
* @param CompanyRepository $company_repo
|
||||
@ -225,6 +231,13 @@ class CompanyGatewayController extends BaseController
|
||||
StripeWebhook::dispatch($company_gateway->company->company_key, $company_gateway->id);
|
||||
} elseif($company_gateway->gateway_key == $this->checkout_key) {
|
||||
CheckoutSetupWebhook::dispatch($company_gateway->company->company_key, $company_gateway->id);
|
||||
} elseif($company_gateway->gateway_key == $this->forte_key) {
|
||||
|
||||
dispatch(function () use ($company_gateway) {
|
||||
MultiDB::setDb($company_gateway->company->db);
|
||||
$company_gateway->driver()->updateFees();
|
||||
})->afterResponse();
|
||||
|
||||
}
|
||||
|
||||
return $this->itemResponse($company_gateway);
|
||||
@ -407,6 +420,13 @@ class CompanyGatewayController extends BaseController
|
||||
|
||||
if($company_gateway->gateway_key == $this->checkout_key) {
|
||||
CheckoutSetupWebhook::dispatch($company_gateway->company->company_key, $company_gateway->fresh()->id);
|
||||
}elseif($company_gateway->gateway_key == $this->forte_key){
|
||||
|
||||
dispatch(function () use ($company_gateway) {
|
||||
MultiDB::setDb($company_gateway->company->db);
|
||||
$company_gateway->driver()->updateFees();
|
||||
})->afterResponse();
|
||||
|
||||
}
|
||||
|
||||
return $this->itemResponse($company_gateway);
|
||||
@ -535,4 +555,28 @@ class CompanyGatewayController extends BaseController
|
||||
|
||||
return $this->listResponse(CompanyGateway::withTrashed()->company()->whereIn('id', $request->ids));
|
||||
}
|
||||
|
||||
public function test(TestCompanyGatewayRequest $request, CompanyGateway $company_gateway)
|
||||
{
|
||||
|
||||
return response()->json(['message' => $company_gateway->driver()->auth() ? 'true' : 'false'], 200);
|
||||
|
||||
}
|
||||
|
||||
public function importCustomers(TestCompanyGatewayRequest $request, CompanyGateway $company_gateway)
|
||||
{
|
||||
//Throttle here
|
||||
// if (Cache::get("throttle_polling:import_customers:{$company_gateway->company->company_key}:{$company_gateway->hashed_id}"))
|
||||
// return response()->json(['message' => ctrans('texts.import_started')], 200);
|
||||
|
||||
dispatch(function () use($company_gateway) {
|
||||
MultiDB::setDb($company_gateway->company->db);
|
||||
$company_gateway->driver()->importCustomers();
|
||||
})->afterResponse();
|
||||
|
||||
Cache::put("throttle_polling:import_customers:{$company_gateway->company->company_key}:{$company_gateway->hashed_id}", true, 300);
|
||||
|
||||
return response()->json(['message' => ctrans('texts.import_started')], 200);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -727,6 +727,74 @@ class CreditController extends BaseController
|
||||
}, $credit->numberFormatter() . '.pdf', $headers);
|
||||
|
||||
}
|
||||
/**
|
||||
* @OA\Get(
|
||||
* path="/api/v1/credit/{invitation_key}/download_e_credit",
|
||||
* operationId="downloadXcredit",
|
||||
* tags={"credit"},
|
||||
* summary="Download a specific x-credit by invitation key",
|
||||
* description="Downloads a specific x-credit",
|
||||
* @OA\Parameter(ref="#/components/parameters/X-API-TOKEN"),
|
||||
* @OA\Parameter(ref="#/components/parameters/X-Requested-With"),
|
||||
* @OA\Parameter(ref="#/components/parameters/include"),
|
||||
* @OA\Parameter(
|
||||
* name="invitation_key",
|
||||
* in="path",
|
||||
* description="The credit Invitation Key",
|
||||
* example="D2J234DFA",
|
||||
* required=true,
|
||||
* @OA\Schema(
|
||||
* type="string",
|
||||
* format="string",
|
||||
* ),
|
||||
* ),
|
||||
* @OA\Response(
|
||||
* response=200,
|
||||
* description="Returns the x-credit pdf",
|
||||
* @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"),
|
||||
* ),
|
||||
* )
|
||||
* @param $invitation_key
|
||||
* @return \Symfony\Component\HttpFoundation\BinaryFileResponse
|
||||
*/
|
||||
public function downloadECredit($invitation_key)
|
||||
{
|
||||
$invitation = $this->credit_repository->getInvitationByKey($invitation_key);
|
||||
|
||||
if (! $invitation) {
|
||||
return response()->json(['message' => 'no record found'], 400);
|
||||
}
|
||||
|
||||
$contact = $invitation->contact;
|
||||
$credit = $invitation->credit;
|
||||
|
||||
$file = $credit->service()->getEInvoice($contact);
|
||||
$file_name = $credit->getFileName("xml");
|
||||
|
||||
$headers = ['Content-Type' => 'application/xml'];
|
||||
|
||||
if (request()->input('inline') == 'true') {
|
||||
$headers = array_merge($headers, ['Content-Disposition' => 'inline']);
|
||||
}
|
||||
|
||||
return response()->streamDownload(function () use ($file) {
|
||||
echo $file;
|
||||
}, $file_name, $headers);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Update the specified resource in storage.
|
||||
|
@ -63,8 +63,12 @@ class LogoutController extends BaseController
|
||||
$ct->company
|
||||
->tokens()
|
||||
->where('is_system', true)
|
||||
->forceDelete();
|
||||
|
||||
->cursor()
|
||||
->each(function ($ct){
|
||||
$ct->token = \Illuminate\Support\Str::random(64);
|
||||
$ct->save();
|
||||
});
|
||||
|
||||
return response()->json(['message' => 'All tokens deleted'], 200);
|
||||
}
|
||||
}
|
||||
|
@ -851,4 +851,71 @@ class PurchaseOrderController extends BaseController
|
||||
echo $file;
|
||||
}, $purchase_order->numberFormatter().".pdf", $headers);
|
||||
}
|
||||
/**
|
||||
* @OA\Get(
|
||||
* path="/api/v1/credit/{invitation_key}/download_e_purchase_order",
|
||||
* operationId="downloadEPurchaseOrder",
|
||||
* tags={"purchase_orders"},
|
||||
* summary="Download a specific E-Purchase-Order by invitation key",
|
||||
* description="Downloads a specific E-Purchase-Order",
|
||||
* @OA\Parameter(ref="#/components/parameters/X-API-TOKEN"),
|
||||
* @OA\Parameter(ref="#/components/parameters/X-Requested-With"),
|
||||
* @OA\Parameter(ref="#/components/parameters/include"),
|
||||
* @OA\Parameter(
|
||||
* name="invitation_key",
|
||||
* in="path",
|
||||
* description="The E-Purchase-Order Invitation Key",
|
||||
* example="D2J234DFA",
|
||||
* required=true,
|
||||
* @OA\Schema(
|
||||
* type="string",
|
||||
* format="string",
|
||||
* ),
|
||||
* ),
|
||||
* @OA\Response(
|
||||
* response=200,
|
||||
* description="Returns the E-Purchase-Order pdf",
|
||||
* @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"),
|
||||
* ),
|
||||
* )
|
||||
* @param $invitation_key
|
||||
* @return \Symfony\Component\HttpFoundation\BinaryFileResponse
|
||||
*/
|
||||
public function downloadEPurchaseOrder($invitation_key)
|
||||
{
|
||||
$invitation = $this->purchase_order_repository->getInvitationByKey($invitation_key);
|
||||
|
||||
if (! $invitation) {
|
||||
return response()->json(['message' => 'no record found'], 400);
|
||||
}
|
||||
|
||||
$contact = $invitation->contact;
|
||||
$purchase_order = $invitation->purchase_order;
|
||||
|
||||
$file = $purchase_order->service()->getEPurchaseOrder($contact);
|
||||
$file_name = $purchase_order->getFileName("xml");
|
||||
|
||||
$headers = ['Content-Type' => 'application/xml'];
|
||||
|
||||
if (request()->input('inline') == 'true') {
|
||||
$headers = array_merge($headers, ['Content-Disposition' => 'inline']);
|
||||
}
|
||||
|
||||
return response()->streamDownload(function () use ($file) {
|
||||
echo $file;
|
||||
}, $file_name, $headers);
|
||||
}
|
||||
}
|
||||
|
@ -860,6 +860,75 @@ class QuoteController extends BaseController
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @OA\Get(
|
||||
* path="/api/v1/invoice/{invitation_key}/download_e_quote",
|
||||
* operationId="downloadXQuote",
|
||||
* tags={"quotes"},
|
||||
* summary="Download a specific x-quote by invitation key",
|
||||
* description="Downloads a specific x-quote",
|
||||
* @OA\Parameter(ref="#/components/parameters/X-API-TOKEN"),
|
||||
* @OA\Parameter(ref="#/components/parameters/X-Requested-With"),
|
||||
* @OA\Parameter(ref="#/components/parameters/include"),
|
||||
* @OA\Parameter(
|
||||
* name="invitation_key",
|
||||
* in="path",
|
||||
* description="The Quote Invitation Key",
|
||||
* example="D2J234DFA",
|
||||
* required=true,
|
||||
* @OA\Schema(
|
||||
* type="string",
|
||||
* format="string",
|
||||
* ),
|
||||
* ),
|
||||
* @OA\Response(
|
||||
* response=200,
|
||||
* description="Returns the x-quote pdf",
|
||||
* @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"),
|
||||
* ),
|
||||
* )
|
||||
* @param $invitation_key
|
||||
* @return \Symfony\Component\HttpFoundation\BinaryFileResponse
|
||||
*/
|
||||
public function downloadEQuote($invitation_key)
|
||||
{
|
||||
$invitation = $this->quote_repo->getInvitationByKey($invitation_key);
|
||||
|
||||
if (! $invitation) {
|
||||
return response()->json(['message' => 'no record found'], 400);
|
||||
}
|
||||
|
||||
$contact = $invitation->contact;
|
||||
$quote = $invitation->quote;
|
||||
|
||||
$file = $quote->service()->getEInvoice($contact);
|
||||
$file_name = $quote->getFileName("xml");
|
||||
|
||||
$headers = ['Content-Type' => 'application/xml'];
|
||||
|
||||
if (request()->input('inline') == 'true') {
|
||||
$headers = array_merge($headers, ['Content-Disposition' => 'inline']);
|
||||
}
|
||||
|
||||
return response()->streamDownload(function () use ($file) {
|
||||
echo $file;
|
||||
}, $file_name, $headers);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Update the specified resource in storage.
|
||||
*
|
||||
|
@ -55,7 +55,17 @@ class SmtpController extends BaseController
|
||||
(new \Illuminate\Mail\MailServiceProvider(app()))->register();
|
||||
|
||||
try {
|
||||
Mail::mailer('smtp')->to($user->email, $user->present()->name())->send(new TestMailServer('Email Server Works!', strlen($company->settings->custom_sending_email) > 1 ? $company->settings->custom_sending_email : $user->email));
|
||||
|
||||
$sending_email = (isset($company->settings->custom_sending_email) && stripos($company->settings->custom_sending_email, "@")) ? $company->settings->custom_sending_email : $user->email;
|
||||
$sending_user = (isset($company->settings->email_from_name) && strlen($company->settings->email_from_name) > 2) ? $company->settings->email_from_name : $user->name();
|
||||
|
||||
$mailable = new TestMailServer('Email Server Works!', $sending_email);
|
||||
$mailable->from($sending_email,$sending_user);
|
||||
|
||||
Mail::mailer('smtp')
|
||||
->to($user->email, $user->present()->name())
|
||||
->send($mailable);
|
||||
|
||||
} catch (\Exception $e) {
|
||||
app('mail.manager')->forgetMailers();
|
||||
return response()->json(['message' => $e->getMessage()], 400);
|
||||
|
@ -260,8 +260,8 @@ class UserController extends BaseController
|
||||
/** @var \App\Models\User $logged_in_user */
|
||||
$logged_in_user = auth()->user();
|
||||
|
||||
$company_user = CompanyUser::whereUserId($user->id)
|
||||
->whereCompanyId($logged_in_user->companyId())
|
||||
$company_user = CompanyUser::where('user_id',$user->id)
|
||||
->where('company_id', $logged_in_user->companyId())
|
||||
->withTrashed()
|
||||
->first();
|
||||
|
||||
@ -269,14 +269,10 @@ class UserController extends BaseController
|
||||
return response()->json(['message', 'Cannot detach owner.'], 401);
|
||||
}
|
||||
|
||||
$token = $company_user->token->where('company_id', $company_user->company_id)->where('user_id', $company_user->user_id)->first();
|
||||
|
||||
if ($token) {
|
||||
$token->delete();
|
||||
}
|
||||
$company_user->tokens()->where('company_id', $company_user->company_id)->where('user_id', $company_user->user_id)->forceDelete();
|
||||
|
||||
if ($company_user) {
|
||||
$company_user->delete();
|
||||
$company_user->forceDelete();
|
||||
}
|
||||
|
||||
return response()->json(['message' => ctrans('texts.user_detached')], 200);
|
||||
|
@ -33,15 +33,15 @@ class UploadBankIntegrationRequest extends Request
|
||||
$rules = [];
|
||||
|
||||
if ($this->file('documents') && is_array($this->file('documents'))) {
|
||||
$rules['documents.*'] = $this->file_validation;
|
||||
$rules['documents.*'] = $this->fileValidation();
|
||||
} elseif ($this->file('documents')) {
|
||||
$rules['documents'] = $this->file_validation;
|
||||
$rules['documents'] = $this->fileValidation();
|
||||
}
|
||||
|
||||
if ($this->file('file') && is_array($this->file('file'))) {
|
||||
$rules['file.*'] = $this->file_validation;
|
||||
$rules['file.*'] = $this->fileValidation();
|
||||
} elseif ($this->file('file')) {
|
||||
$rules['file'] = $this->file_validation;
|
||||
$rules['file'] = $this->fileValidation();
|
||||
}
|
||||
|
||||
$rules['is_public'] = 'sometimes|boolean';
|
||||
|
@ -33,15 +33,15 @@ class UploadBankTransactionRequest extends Request
|
||||
$rules = [];
|
||||
|
||||
if ($this->file('documents') && is_array($this->file('documents'))) {
|
||||
$rules['documents.*'] = $this->file_validation;
|
||||
$rules['documents.*'] = $this->fileValidation();
|
||||
} elseif ($this->file('documents')) {
|
||||
$rules['documents'] = $this->file_validation;
|
||||
$rules['documents'] = $this->fileValidation();
|
||||
}
|
||||
|
||||
if ($this->file('file') && is_array($this->file('file'))) {
|
||||
$rules['file.*'] = $this->file_validation;
|
||||
$rules['file.*'] = $this->fileValidation();
|
||||
} elseif ($this->file('file')) {
|
||||
$rules['file'] = $this->file_validation;
|
||||
$rules['file'] = $this->fileValidation();
|
||||
}
|
||||
|
||||
$rules['is_public'] = 'sometimes|boolean';
|
||||
|
@ -45,18 +45,18 @@ class StoreClientRequest extends Request
|
||||
$user = auth()->user();
|
||||
|
||||
if ($this->file('documents') && is_array($this->file('documents'))) {
|
||||
$rules['documents.*'] = $this->file_validation;
|
||||
$rules['documents.*'] = $this->fileValidation();
|
||||
} elseif ($this->file('documents')) {
|
||||
$rules['documents'] = $this->file_validation;
|
||||
$rules['documents'] = $this->fileValidation();
|
||||
}
|
||||
else {
|
||||
$rules['documents'] = 'bail|sometimes|array';
|
||||
}
|
||||
|
||||
if ($this->file('file') && is_array($this->file('file'))) {
|
||||
$rules['file.*'] = $this->file_validation;
|
||||
$rules['file.*'] = $this->fileValidation();
|
||||
} elseif ($this->file('file')) {
|
||||
$rules['file'] = $this->file_validation;
|
||||
$rules['file'] = $this->fileValidation();
|
||||
}
|
||||
|
||||
/* Ensure we have a client name, and that all emails are unique*/
|
||||
|
@ -44,15 +44,15 @@ class UpdateClientRequest extends Request
|
||||
$user = auth()->user();
|
||||
|
||||
if ($this->file('documents') && is_array($this->file('documents'))) {
|
||||
$rules['documents.*'] = $this->file_validation;
|
||||
$rules['documents.*'] = $this->fileValidation();
|
||||
} elseif ($this->file('documents')) {
|
||||
$rules['documents'] = $this->file_validation;
|
||||
$rules['documents'] = $this->fileValidation();
|
||||
}
|
||||
|
||||
if ($this->file('file') && is_array($this->file('file'))) {
|
||||
$rules['file.*'] = $this->file_validation;
|
||||
$rules['file.*'] = $this->fileValidation();
|
||||
} elseif ($this->file('file')) {
|
||||
$rules['file'] = $this->file_validation;
|
||||
$rules['file'] = $this->fileValidation();
|
||||
} else {
|
||||
$rules['documents'] = 'bail|sometimes|array';
|
||||
}
|
||||
|
@ -33,15 +33,15 @@ class UploadClientRequest extends Request
|
||||
$rules = [];
|
||||
|
||||
if ($this->file('documents') && is_array($this->file('documents'))) {
|
||||
$rules['documents.*'] = $this->file_validation;
|
||||
$rules['documents.*'] = $this->fileValidation();
|
||||
} elseif ($this->file('documents')) {
|
||||
$rules['documents'] = $this->file_validation;
|
||||
$rules['documents'] = $this->fileValidation();
|
||||
}
|
||||
|
||||
if ($this->file('file') && is_array($this->file('file'))) {
|
||||
$rules['file.*'] = $this->file_validation;
|
||||
$rules['file.*'] = $this->fileValidation();
|
||||
} elseif ($this->file('file')) {
|
||||
$rules['file'] = $this->file_validation;
|
||||
$rules['file'] = $this->fileValidation();
|
||||
}
|
||||
|
||||
$rules['is_public'] = 'sometimes|boolean';
|
||||
|
@ -30,15 +30,15 @@ class UploadCompanyRequest extends Request
|
||||
$rules = [];
|
||||
|
||||
if ($this->file('documents') && is_array($this->file('documents'))) {
|
||||
$rules['documents.*'] = $this->file_validation;
|
||||
$rules['documents.*'] = $this->fileValidation();
|
||||
} elseif ($this->file('documents')) {
|
||||
$rules['documents'] = $this->file_validation;
|
||||
$rules['documents'] = $this->fileValidation();
|
||||
}
|
||||
|
||||
if ($this->file('file') && is_array($this->file('file'))) {
|
||||
$rules['file.*'] = $this->file_validation;
|
||||
$rules['file.*'] = $this->fileValidation();
|
||||
} elseif ($this->file('file')) {
|
||||
$rules['file'] = $this->file_validation;
|
||||
$rules['file'] = $this->fileValidation();
|
||||
}
|
||||
|
||||
return $rules;
|
||||
|
@ -0,0 +1,49 @@
|
||||
<?php
|
||||
/**
|
||||
* Invoice Ninja (https://invoiceninja.com).
|
||||
*
|
||||
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||
*
|
||||
* @copyright Copyright (c) 2023. Invoice Ninja LLC (https://invoiceninja.com)
|
||||
*
|
||||
* @license https://www.elastic.co/licensing/elastic-license
|
||||
*/
|
||||
|
||||
namespace App\Http\Requests\CompanyGateway;
|
||||
|
||||
use App\Http\Requests\Request;
|
||||
use App\Utils\Traits\MakesHash;
|
||||
use Illuminate\Validation\Rule;
|
||||
|
||||
class TestCompanyGatewayRequest extends Request
|
||||
{
|
||||
use MakesHash;
|
||||
|
||||
/**
|
||||
* Determine if the user is authorized to make this request.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function authorize(): bool
|
||||
{
|
||||
/** @var \App\Models\User $user */
|
||||
$user = auth()->user();
|
||||
|
||||
return $user->isAdmin();
|
||||
}
|
||||
|
||||
public function rules()
|
||||
{
|
||||
|
||||
return [
|
||||
|
||||
];
|
||||
}
|
||||
|
||||
public function prepareForValidation()
|
||||
{
|
||||
$input = $this->all();
|
||||
|
||||
$this->replace($input);
|
||||
}
|
||||
}
|
@ -47,17 +47,17 @@ class StoreCreditRequest extends Request
|
||||
$rules = [];
|
||||
|
||||
if ($this->file('documents') && is_array($this->file('documents'))) {
|
||||
$rules['documents.*'] = $this->file_validation;
|
||||
$rules['documents.*'] = $this->fileValidation();
|
||||
} elseif ($this->file('documents')) {
|
||||
$rules['documents'] = $this->file_validation;
|
||||
$rules['documents'] = $this->fileValidation();
|
||||
}else {
|
||||
$rules['documents'] = 'bail|sometimes|array';
|
||||
}
|
||||
|
||||
if ($this->file('file') && is_array($this->file('file'))) {
|
||||
$rules['file.*'] = $this->file_validation;
|
||||
$rules['file.*'] = $this->fileValidation();
|
||||
} elseif ($this->file('file')) {
|
||||
$rules['file'] = $this->file_validation;
|
||||
$rules['file'] = $this->fileValidation();
|
||||
}
|
||||
|
||||
/** @var \App\Models\User $user */
|
||||
|
@ -49,17 +49,17 @@ class UpdateCreditRequest extends Request
|
||||
$rules = [];
|
||||
|
||||
if ($this->file('documents') && is_array($this->file('documents'))) {
|
||||
$rules['documents.*'] = $this->file_validation;
|
||||
$rules['documents.*'] = $this->fileValidation();
|
||||
} elseif ($this->file('documents')) {
|
||||
$rules['documents'] = $this->file_validation;
|
||||
$rules['documents'] = $this->fileValidation();
|
||||
}else {
|
||||
$rules['documents'] = 'bail|sometimes|array';
|
||||
}
|
||||
|
||||
if ($this->file('file') && is_array($this->file('file'))) {
|
||||
$rules['file.*'] = $this->file_validation;
|
||||
$rules['file.*'] = $this->fileValidation();
|
||||
} elseif ($this->file('file')) {
|
||||
$rules['file'] = $this->file_validation;
|
||||
$rules['file'] = $this->fileValidation();
|
||||
}
|
||||
|
||||
$rules['number'] = ['bail', 'sometimes', 'nullable', Rule::unique('credits')->where('company_id', $user->company()->id)->ignore($this->credit->id)];
|
||||
|
@ -33,15 +33,15 @@ class UploadCreditRequest extends Request
|
||||
$rules = [];
|
||||
|
||||
if ($this->file('documents') && is_array($this->file('documents'))) {
|
||||
$rules['documents.*'] = $this->file_validation;
|
||||
$rules['documents.*'] = $this->fileValidation();
|
||||
} elseif ($this->file('documents')) {
|
||||
$rules['documents'] = $this->file_validation;
|
||||
$rules['documents'] = $this->fileValidation();
|
||||
}
|
||||
|
||||
if ($this->file('file') && is_array($this->file('file'))) {
|
||||
$rules['file.*'] = $this->file_validation;
|
||||
$rules['file.*'] = $this->fileValidation();
|
||||
} elseif ($this->file('file')) {
|
||||
$rules['file'] = $this->file_validation;
|
||||
$rules['file'] = $this->fileValidation();
|
||||
}
|
||||
|
||||
$rules['is_public'] = 'sometimes|boolean';
|
||||
|
@ -33,15 +33,15 @@ class UploadExpenseRequest extends Request
|
||||
$rules = [];
|
||||
|
||||
if ($this->file('documents') && is_array($this->file('documents'))) {
|
||||
$rules['documents.*'] = $this->file_validation;
|
||||
$rules['documents.*'] = $this->fileValidation();
|
||||
} elseif ($this->file('documents')) {
|
||||
$rules['documents'] = $this->file_validation;
|
||||
$rules['documents'] = $this->fileValidation();
|
||||
}
|
||||
|
||||
if ($this->file('file') && is_array($this->file('file'))) {
|
||||
$rules['file.*'] = $this->file_validation;
|
||||
$rules['file.*'] = $this->fileValidation();
|
||||
} elseif ($this->file('file')) {
|
||||
$rules['file'] = $this->file_validation;
|
||||
$rules['file'] = $this->fileValidation();
|
||||
}
|
||||
|
||||
$rules['is_public'] = 'sometimes|boolean';
|
||||
|
@ -30,15 +30,15 @@ class UploadGroupSettingRequest extends Request
|
||||
$rules = [];
|
||||
|
||||
if ($this->file('documents') && is_array($this->file('documents'))) {
|
||||
$rules['documents.*'] = $this->file_validation;
|
||||
$rules['documents.*'] = $this->fileValidation();
|
||||
} elseif ($this->file('documents')) {
|
||||
$rules['documents'] = $this->file_validation;
|
||||
$rules['documents'] = $this->fileValidation();
|
||||
}
|
||||
|
||||
if ($this->file('file') && is_array($this->file('file'))) {
|
||||
$rules['file.*'] = $this->file_validation;
|
||||
$rules['file.*'] = $this->fileValidation();
|
||||
} elseif ($this->file('file')) {
|
||||
$rules['file'] = $this->file_validation;
|
||||
$rules['file'] = $this->fileValidation();
|
||||
}
|
||||
|
||||
return $rules;
|
||||
|
@ -44,17 +44,17 @@ class StoreInvoiceRequest extends Request
|
||||
$user = auth()->user();
|
||||
|
||||
if ($this->file('documents') && is_array($this->file('documents'))) {
|
||||
$rules['documents.*'] = $this->file_validation;
|
||||
$rules['documents.*'] = $this->fileValidation();
|
||||
} elseif ($this->file('documents')) {
|
||||
$rules['documents'] = $this->file_validation;
|
||||
$rules['documents'] = $this->fileValidation();
|
||||
}else {
|
||||
$rules['documents'] = 'bail|sometimes|array';
|
||||
}
|
||||
|
||||
if ($this->file('file') && is_array($this->file('file'))) {
|
||||
$rules['file.*'] = $this->file_validation;
|
||||
$rules['file.*'] = $this->fileValidation();
|
||||
} elseif ($this->file('file')) {
|
||||
$rules['file'] = $this->file_validation;
|
||||
$rules['file'] = $this->fileValidation();
|
||||
}
|
||||
|
||||
$rules['client_id'] = 'bail|required|exists:clients,id,company_id,'.$user->company()->id.',is_deleted,0';
|
||||
|
@ -46,17 +46,17 @@ class UpdateInvoiceRequest extends Request
|
||||
$rules = [];
|
||||
|
||||
if ($this->file('documents') && is_array($this->file('documents'))) {
|
||||
$rules['documents.*'] = $this->file_validation;
|
||||
$rules['documents.*'] = $this->fileValidation();
|
||||
} elseif ($this->file('documents')) {
|
||||
$rules['documents'] = $this->file_validation;
|
||||
$rules['documents'] = $this->fileValidation();
|
||||
}else {
|
||||
$rules['documents'] = 'bail|sometimes|array';
|
||||
}
|
||||
|
||||
if ($this->file('file') && is_array($this->file('file'))) {
|
||||
$rules['file.*'] = $this->file_validation;
|
||||
$rules['file.*'] = $this->fileValidation();
|
||||
} elseif ($this->file('file')) {
|
||||
$rules['file'] = $this->file_validation;
|
||||
$rules['file'] = $this->fileValidation();
|
||||
}
|
||||
|
||||
// $rules['id'] = new LockedInvoiceRule($this->invoice);
|
||||
|
@ -33,15 +33,15 @@ class UploadInvoiceRequest extends Request
|
||||
$rules = [];
|
||||
|
||||
if ($this->file('documents') && is_array($this->file('documents'))) {
|
||||
$rules['documents.*'] = $this->file_validation;
|
||||
$rules['documents.*'] = $this->fileValidation();
|
||||
} elseif ($this->file('documents')) {
|
||||
$rules['documents'] = $this->file_validation;
|
||||
$rules['documents'] = $this->fileValidation();
|
||||
}
|
||||
|
||||
if ($this->file('file') && is_array($this->file('file'))) {
|
||||
$rules['file.*'] = $this->file_validation;
|
||||
$rules['file.*'] = $this->fileValidation();
|
||||
} elseif ($this->file('file')) {
|
||||
$rules['file'] = $this->file_validation;
|
||||
$rules['file'] = $this->fileValidation();
|
||||
}
|
||||
|
||||
$rules['is_public'] = 'sometimes|boolean';
|
||||
|
@ -57,8 +57,6 @@ class RefundPaymentRequest extends Request
|
||||
|
||||
if (isset($input['credits'])) {
|
||||
unset($input['credits']);
|
||||
// foreach($input['credits'] as $key => $credit)
|
||||
// $input['credits'][$key]['credit_id'] = $this->decodePrimaryKey($credit['credit_id']);
|
||||
}
|
||||
|
||||
$this->replace($input);
|
||||
|
@ -16,7 +16,6 @@ use App\Http\ValidationRules\Credit\CreditsSumRule;
|
||||
use App\Http\ValidationRules\Credit\ValidCreditsRules;
|
||||
use App\Http\ValidationRules\Payment\ValidInvoicesRules;
|
||||
use App\Http\ValidationRules\PaymentAmountsBalanceRule;
|
||||
use App\Http\ValidationRules\ValidCreditsPresentRule;
|
||||
use App\Http\ValidationRules\ValidPayableInvoicesRule;
|
||||
use App\Models\Payment;
|
||||
use App\Utils\Traits\MakesHash;
|
||||
@ -39,6 +38,41 @@ class StorePaymentRequest extends Request
|
||||
return $user->can('create', Payment::class);
|
||||
}
|
||||
|
||||
public function rules()
|
||||
{
|
||||
/** @var \App\Models\User $user */
|
||||
$user = auth()->user();
|
||||
|
||||
$rules = [
|
||||
'client_id' => ['bail','required',Rule::exists('clients','id')->where('company_id',$user->company()->id)->where('is_deleted', 0)],
|
||||
'amount' => ['bail', 'numeric', new PaymentAmountsBalanceRule()],
|
||||
'invoices.*.amount' => ['bail','required'],
|
||||
'invoices.*.invoice_id' => ['bail','required','distinct', new ValidInvoicesRules($this->all()),Rule::exists('invoices','id')->where('company_id', $user->company()->id)->where('client_id', $this->client_id)],
|
||||
'credits.*.credit_id' => ['bail','required','distinct', new ValidCreditsRules($this->all()),Rule::exists('credits','id')->where('company_id', $user->company()->id)->where('client_id', $this->client_id)],
|
||||
'credits.*.amount' => ['bail','required', new CreditsSumRule($this->all())],
|
||||
'invoices' => ['bail','sometimes', 'nullable', 'array', new ValidPayableInvoicesRule()],
|
||||
'number' => ['bail', 'nullable', Rule::unique('payments')->where('company_id', $user->company()->id)],
|
||||
'idempotency_key' => ['nullable', 'bail', 'string','max:64', Rule::unique('payments')->where('company_id', $user->company()->id)],
|
||||
];
|
||||
|
||||
if ($this->file('documents') && is_array($this->file('documents'))) {
|
||||
$rules['documents.*'] = $this->fileValidation();
|
||||
} elseif ($this->file('documents')) {
|
||||
$rules['documents'] = $this->fileValidation();
|
||||
}else {
|
||||
$rules['documents'] = 'bail|sometimes|array';
|
||||
}
|
||||
|
||||
if ($this->file('file') && is_array($this->file('file'))) {
|
||||
$rules['file.*'] = $this->fileValidation();
|
||||
} elseif ($this->file('file')) {
|
||||
$rules['file'] = $this->fileValidation();
|
||||
}
|
||||
|
||||
return $rules;
|
||||
}
|
||||
|
||||
|
||||
public function prepareForValidation()
|
||||
{
|
||||
|
||||
@ -78,7 +112,6 @@ class StorePaymentRequest extends Request
|
||||
foreach ($input['credits'] as $key => $value) {
|
||||
if (array_key_exists('credit_id', $input['credits'][$key])) {
|
||||
$input['credits'][$key]['credit_id'] = $this->decodePrimaryKey($value['credit_id']);
|
||||
|
||||
$credits_total += $value['amount'];
|
||||
}
|
||||
}
|
||||
@ -103,39 +136,5 @@ class StorePaymentRequest extends Request
|
||||
$this->replace($input);
|
||||
}
|
||||
|
||||
public function rules()
|
||||
{
|
||||
/** @var \App\Models\User $user */
|
||||
$user = auth()->user();
|
||||
|
||||
$rules = [
|
||||
'amount' => ['numeric', 'bail', new PaymentAmountsBalanceRule(), new ValidCreditsPresentRule($this->all())],
|
||||
'client_id' => 'bail|required|exists:clients,id,company_id,'.$user->company()->id.',is_deleted,0',
|
||||
'invoices.*.invoice_id' => 'bail|required|distinct|exists:invoices,id',
|
||||
'invoices.*.amount' => 'bail|required',
|
||||
'invoices.*.invoice_id' => new ValidInvoicesRules($this->all()),
|
||||
'credits.*.credit_id' => 'bail|required|exists:credits,id',
|
||||
'credits.*.credit_id' => new ValidCreditsRules($this->all()),
|
||||
'credits.*.amount' => ['bail','required', new CreditsSumRule($this->all())],
|
||||
'invoices' => new ValidPayableInvoicesRule(),
|
||||
'number' => ['nullable', 'bail', Rule::unique('payments')->where('company_id', $user->company()->id)],
|
||||
'idempotency_key' => ['nullable', 'bail', 'string','max:64', Rule::unique('payments')->where('company_id', $user->company()->id)],
|
||||
];
|
||||
|
||||
if ($this->file('documents') && is_array($this->file('documents'))) {
|
||||
$rules['documents.*'] = $this->file_validation;
|
||||
} elseif ($this->file('documents')) {
|
||||
$rules['documents'] = $this->file_validation;
|
||||
}else {
|
||||
$rules['documents'] = 'bail|sometimes|array';
|
||||
}
|
||||
|
||||
if ($this->file('file') && is_array($this->file('file'))) {
|
||||
$rules['file.*'] = $this->file_validation;
|
||||
} elseif ($this->file('file')) {
|
||||
$rules['file'] = $this->file_validation;
|
||||
}
|
||||
|
||||
return $rules;
|
||||
}
|
||||
}
|
||||
|
@ -13,7 +13,6 @@ namespace App\Http\Requests\Payment;
|
||||
|
||||
use App\Http\Requests\Request;
|
||||
use App\Http\ValidationRules\PaymentAppliedValidAmount;
|
||||
use App\Http\ValidationRules\ValidCreditsPresentRule;
|
||||
use App\Utils\Traits\ChecksEntityStatus;
|
||||
use App\Utils\Traits\MakesHash;
|
||||
use Illuminate\Validation\Rule;
|
||||
@ -41,28 +40,29 @@ class UpdatePaymentRequest extends Request
|
||||
|
||||
/** @var \App\Models\User $user */
|
||||
$user = auth()->user();
|
||||
|
||||
|
||||
$rules = [
|
||||
'invoices' => ['array', new PaymentAppliedValidAmount($this->all()), new ValidCreditsPresentRule($this->all())],
|
||||
'invoices.*.invoice_id' => 'distinct',
|
||||
'client_id' => ['sometimes', 'bail', Rule::in([$this->payment->client_id])],
|
||||
'number' => ['sometimes', 'bail', Rule::unique('payments')->where('company_id', $user->company()->id)->ignore($this->payment->id)],
|
||||
'invoices' => ['sometimes', 'bail', 'nullable', 'array', new PaymentAppliedValidAmount($this->all())],
|
||||
'invoices.*.invoice_id' => ['sometimes','distinct',Rule::exists('invoices','id')->where('company_id', $user->company()->id)->where('client_id', $this->client_id)],
|
||||
'invoices.*.amount' => ['sometimes','numeric','min:0'],
|
||||
'credits.*.credit_id' => ['sometimes','bail','distinct',Rule::exists('credits','id')->where('company_id', $user->company()->id)->where('client_id', $this->client_id)],
|
||||
'credits.*.amount' => ['required', 'bail'],
|
||||
];
|
||||
|
||||
if ($this->number) {
|
||||
$rules['number'] = Rule::unique('payments')->where('company_id', $user->company()->id)->ignore($this->payment->id);
|
||||
}
|
||||
|
||||
if ($this->file('documents') && is_array($this->file('documents'))) {
|
||||
$rules['documents.*'] = $this->file_validation;
|
||||
$rules['documents.*'] = $this->fileValidation();
|
||||
} elseif ($this->file('documents')) {
|
||||
$rules['documents'] = $this->file_validation;
|
||||
$rules['documents'] = $this->fileValidation();
|
||||
}else {
|
||||
$rules['documents'] = 'bail|sometimes|array';
|
||||
}
|
||||
|
||||
if ($this->file('file') && is_array($this->file('file'))) {
|
||||
$rules['file.*'] = $this->file_validation;
|
||||
$rules['file.*'] = $this->fileValidation();
|
||||
} elseif ($this->file('file')) {
|
||||
$rules['file'] = $this->file_validation;
|
||||
$rules['file'] = $this->fileValidation();
|
||||
}
|
||||
|
||||
return $rules;
|
||||
@ -74,10 +74,6 @@ class UpdatePaymentRequest extends Request
|
||||
|
||||
$input = $this->decodePrimaryKeys($input);
|
||||
|
||||
if (isset($input['client_id'])) {
|
||||
unset($input['client_id']);
|
||||
}
|
||||
|
||||
if (isset($input['amount'])) {
|
||||
unset($input['amount']);
|
||||
}
|
||||
@ -85,7 +81,6 @@ class UpdatePaymentRequest extends Request
|
||||
if (isset($input['invoices']) && is_array($input['invoices']) !== false) {
|
||||
foreach ($input['invoices'] as $key => $value) {
|
||||
if(isset($input['invoices'][$key]['invoice_id'])) {
|
||||
// if (array_key_exists('invoice_id', $input['invoices'][$key])) {
|
||||
$input['invoices'][$key]['invoice_id'] = $this->decodePrimaryKey($value['invoice_id']);
|
||||
}
|
||||
}
|
||||
@ -93,7 +88,6 @@ class UpdatePaymentRequest extends Request
|
||||
|
||||
if (isset($input['credits']) && is_array($input['credits']) !== false) {
|
||||
foreach ($input['credits'] as $key => $value) {
|
||||
// if (array_key_exists('credits', $input['credits'][$key])) {
|
||||
if (isset($input['credits'][$key]['credit_id'])) {
|
||||
$input['credits'][$key]['credit_id'] = $this->decodePrimaryKey($value['credit_id']);
|
||||
}
|
||||
|
@ -33,15 +33,15 @@ class UploadPaymentRequest extends Request
|
||||
$rules = [];
|
||||
|
||||
if ($this->file('documents') && is_array($this->file('documents'))) {
|
||||
$rules['documents.*'] = $this->file_validation;
|
||||
$rules['documents.*'] = $this->fileValidation();
|
||||
} elseif ($this->file('documents')) {
|
||||
$rules['documents'] = $this->file_validation;
|
||||
$rules['documents'] = $this->fileValidation();
|
||||
}
|
||||
|
||||
if ($this->file('file') && is_array($this->file('file'))) {
|
||||
$rules['file.*'] = $this->file_validation;
|
||||
$rules['file.*'] = $this->fileValidation();
|
||||
} elseif ($this->file('file')) {
|
||||
$rules['file'] = $this->file_validation;
|
||||
$rules['file'] = $this->fileValidation();
|
||||
}
|
||||
|
||||
$rules['is_public'] = 'sometimes|boolean';
|
||||
|
@ -32,17 +32,17 @@ class StoreProductRequest extends Request
|
||||
public function rules()
|
||||
{
|
||||
if ($this->file('documents') && is_array($this->file('documents'))) {
|
||||
$rules['documents.*'] = $this->file_validation;
|
||||
$rules['documents.*'] = $this->fileValidation();
|
||||
} elseif ($this->file('documents')) {
|
||||
$rules['documents'] = $this->file_validation;
|
||||
$rules['documents'] = $this->fileValidation();
|
||||
}else {
|
||||
$rules['documents'] = 'bail|sometimes|array';
|
||||
}
|
||||
|
||||
if ($this->file('file') && is_array($this->file('file'))) {
|
||||
$rules['file.*'] = $this->file_validation;
|
||||
$rules['file.*'] = $this->fileValidation();
|
||||
} elseif ($this->file('file')) {
|
||||
$rules['file'] = $this->file_validation;
|
||||
$rules['file'] = $this->fileValidation();
|
||||
}
|
||||
|
||||
$rules['cost'] = 'sometimes|numeric';
|
||||
|
@ -35,17 +35,17 @@ class UpdateProductRequest extends Request
|
||||
public function rules()
|
||||
{
|
||||
if ($this->file('documents') && is_array($this->file('documents'))) {
|
||||
$rules['documents.*'] = $this->file_validation;
|
||||
$rules['documents.*'] = $this->fileValidation();
|
||||
} elseif ($this->file('documents')) {
|
||||
$rules['documents'] = $this->file_validation;
|
||||
$rules['documents'] = $this->fileValidation();
|
||||
}else {
|
||||
$rules['documents'] = 'bail|sometimes|array';
|
||||
}
|
||||
|
||||
if ($this->file('file') && is_array($this->file('file'))) {
|
||||
$rules['file.*'] = $this->file_validation;
|
||||
$rules['file.*'] = $this->fileValidation();
|
||||
} elseif ($this->file('file')) {
|
||||
$rules['file'] = $this->file_validation;
|
||||
$rules['file'] = $this->fileValidation();
|
||||
}
|
||||
|
||||
$rules['cost'] = 'numeric';
|
||||
|
@ -32,15 +32,15 @@ class UploadProductRequest extends Request
|
||||
{
|
||||
$rules = [];
|
||||
if ($this->file('documents') && is_array($this->file('documents'))) {
|
||||
$rules['documents.*'] = $this->file_validation;
|
||||
$rules['documents.*'] = $this->fileValidation();
|
||||
} elseif ($this->file('documents')) {
|
||||
$rules['documents'] = $this->file_validation;
|
||||
$rules['documents'] = $this->fileValidation();
|
||||
}
|
||||
|
||||
if ($this->file('file') && is_array($this->file('file'))) {
|
||||
$rules['file.*'] = $this->file_validation;
|
||||
$rules['file.*'] = $this->fileValidation();
|
||||
} elseif ($this->file('file')) {
|
||||
$rules['file'] = $this->file_validation;
|
||||
$rules['file'] = $this->fileValidation();
|
||||
}
|
||||
|
||||
$rules['is_public'] = 'sometimes|boolean';
|
||||
|
@ -51,17 +51,17 @@ class StoreProjectRequest extends Request
|
||||
}
|
||||
|
||||
if ($this->file('documents') && is_array($this->file('documents'))) {
|
||||
$rules['documents.*'] = $this->file_validation;
|
||||
$rules['documents.*'] = $this->fileValidation();
|
||||
} elseif ($this->file('documents')) {
|
||||
$rules['documents'] = $this->file_validation;
|
||||
$rules['documents'] = $this->fileValidation();
|
||||
}else {
|
||||
$rules['documents'] = 'bail|sometimes|array';
|
||||
}
|
||||
|
||||
if ($this->file('file') && is_array($this->file('file'))) {
|
||||
$rules['file.*'] = $this->file_validation;
|
||||
$rules['file.*'] = $this->fileValidation();
|
||||
} elseif ($this->file('file')) {
|
||||
$rules['file'] = $this->file_validation;
|
||||
$rules['file'] = $this->fileValidation();
|
||||
}
|
||||
|
||||
return $this->globalRules($rules);
|
||||
|
@ -48,17 +48,17 @@ class UpdateProjectRequest extends Request
|
||||
$rules['budgeted_hours'] = 'sometimes|numeric';
|
||||
|
||||
if ($this->file('documents') && is_array($this->file('documents'))) {
|
||||
$rules['documents.*'] = $this->file_validation;
|
||||
$rules['documents.*'] = $this->fileValidation();
|
||||
} elseif ($this->file('documents')) {
|
||||
$rules['documents'] = $this->file_validation;
|
||||
$rules['documents'] = $this->fileValidation();
|
||||
}else {
|
||||
$rules['documents'] = 'bail|sometimes|array';
|
||||
}
|
||||
|
||||
if ($this->file('file') && is_array($this->file('file'))) {
|
||||
$rules['file.*'] = $this->file_validation;
|
||||
$rules['file.*'] = $this->fileValidation();
|
||||
} elseif ($this->file('file')) {
|
||||
$rules['file'] = $this->file_validation;
|
||||
$rules['file'] = $this->fileValidation();
|
||||
}
|
||||
|
||||
return $this->globalRules($rules);
|
||||
|
@ -33,15 +33,15 @@ class UploadProjectRequest extends Request
|
||||
$rules = [];
|
||||
|
||||
if ($this->file('documents') && is_array($this->file('documents'))) {
|
||||
$rules['documents.*'] = $this->file_validation;
|
||||
$rules['documents.*'] = $this->fileValidation();
|
||||
} elseif ($this->file('documents')) {
|
||||
$rules['documents'] = $this->file_validation;
|
||||
$rules['documents'] = $this->fileValidation();
|
||||
}
|
||||
|
||||
if ($this->file('file') && is_array($this->file('file'))) {
|
||||
$rules['file.*'] = $this->file_validation;
|
||||
$rules['file.*'] = $this->fileValidation();
|
||||
} elseif ($this->file('file')) {
|
||||
$rules['file'] = $this->file_validation;
|
||||
$rules['file'] = $this->fileValidation();
|
||||
}
|
||||
|
||||
$rules['is_public'] = 'sometimes|boolean';
|
||||
|
@ -54,17 +54,17 @@ class StorePurchaseOrderRequest extends Request
|
||||
$rules['line_items'] = 'array';
|
||||
|
||||
if ($this->file('documents') && is_array($this->file('documents'))) {
|
||||
$rules['documents.*'] = $this->file_validation;
|
||||
$rules['documents.*'] = $this->fileValidation();
|
||||
} elseif ($this->file('documents')) {
|
||||
$rules['documents'] = $this->file_validation;
|
||||
$rules['documents'] = $this->fileValidation();
|
||||
} else {
|
||||
$rules['documents'] = 'bail|sometimes|array';
|
||||
}
|
||||
|
||||
if ($this->file('file') && is_array($this->file('file'))) {
|
||||
$rules['file.*'] = $this->file_validation;
|
||||
$rules['file.*'] = $this->fileValidation();
|
||||
} elseif ($this->file('file')) {
|
||||
$rules['file'] = $this->file_validation;
|
||||
$rules['file'] = $this->fileValidation();
|
||||
}
|
||||
|
||||
$rules['status_id'] = 'nullable|integer|in:1,2,3,4,5';
|
||||
|
@ -56,17 +56,17 @@ class UpdatePurchaseOrderRequest extends Request
|
||||
$rules['is_amount_discount'] = ['boolean'];
|
||||
|
||||
if ($this->file('documents') && is_array($this->file('documents'))) {
|
||||
$rules['documents.*'] = $this->file_validation;
|
||||
$rules['documents.*'] = $this->fileValidation();
|
||||
} elseif ($this->file('documents')) {
|
||||
$rules['documents'] = $this->file_validation;
|
||||
$rules['documents'] = $this->fileValidation();
|
||||
}else {
|
||||
$rules['documents'] = 'bail|sometimes|array';
|
||||
}
|
||||
|
||||
if ($this->file('file') && is_array($this->file('file'))) {
|
||||
$rules['file.*'] = $this->file_validation;
|
||||
$rules['file.*'] = $this->fileValidation();
|
||||
} elseif ($this->file('file')) {
|
||||
$rules['file'] = $this->file_validation;
|
||||
$rules['file'] = $this->fileValidation();
|
||||
}
|
||||
|
||||
$rules['status_id'] = 'sometimes|integer|in:1,2,3,4,5';
|
||||
|
@ -33,15 +33,15 @@ class UploadPurchaseOrderRequest extends Request
|
||||
$rules = [];
|
||||
|
||||
if ($this->file('documents') && is_array($this->file('documents'))) {
|
||||
$rules['documents.*'] = $this->file_validation;
|
||||
$rules['documents.*'] = $this->fileValidation();
|
||||
} elseif ($this->file('documents')) {
|
||||
$rules['documents'] = $this->file_validation;
|
||||
$rules['documents'] = $this->fileValidation();
|
||||
}
|
||||
|
||||
if ($this->file('file') && is_array($this->file('file'))) {
|
||||
$rules['file.*'] = $this->file_validation;
|
||||
$rules['file.*'] = $this->fileValidation();
|
||||
} elseif ($this->file('file')) {
|
||||
$rules['file'] = $this->file_validation;
|
||||
$rules['file'] = $this->fileValidation();
|
||||
}
|
||||
|
||||
$rules['is_public'] = 'sometimes|boolean';
|
||||
|
@ -46,17 +46,17 @@ class StoreQuoteRequest extends Request
|
||||
$rules['client_id'] = 'required|exists:clients,id,company_id,'.$user->company()->id;
|
||||
|
||||
if ($this->file('documents') && is_array($this->file('documents'))) {
|
||||
$rules['documents.*'] = $this->file_validation;
|
||||
$rules['documents.*'] = $this->fileValidation();
|
||||
} elseif ($this->file('documents')) {
|
||||
$rules['documents'] = $this->file_validation;
|
||||
$rules['documents'] = $this->fileValidation();
|
||||
}else {
|
||||
$rules['documents'] = 'bail|sometimes|array';
|
||||
}
|
||||
|
||||
if ($this->file('file') && is_array($this->file('file'))) {
|
||||
$rules['file.*'] = $this->file_validation;
|
||||
$rules['file.*'] = $this->fileValidation();
|
||||
} elseif ($this->file('file')) {
|
||||
$rules['file'] = $this->file_validation;
|
||||
$rules['file'] = $this->fileValidation();
|
||||
}
|
||||
|
||||
$rules['number'] = ['nullable', Rule::unique('quotes')->where('company_id', $user->company()->id)];
|
||||
|
@ -43,17 +43,17 @@ class UpdateQuoteRequest extends Request
|
||||
$rules = [];
|
||||
|
||||
if ($this->file('documents') && is_array($this->file('documents'))) {
|
||||
$rules['documents.*'] = $this->file_validation;
|
||||
$rules['documents.*'] = $this->fileValidation();
|
||||
} elseif ($this->file('documents')) {
|
||||
$rules['documents'] = $this->file_validation;
|
||||
$rules['documents'] = $this->fileValidation();
|
||||
}else {
|
||||
$rules['documents'] = 'bail|sometimes|array';
|
||||
}
|
||||
|
||||
if ($this->file('file') && is_array($this->file('file'))) {
|
||||
$rules['file.*'] = $this->file_validation;
|
||||
$rules['file.*'] = $this->fileValidation();
|
||||
} elseif ($this->file('file')) {
|
||||
$rules['file'] = $this->file_validation;
|
||||
$rules['file'] = $this->fileValidation();
|
||||
}
|
||||
|
||||
|
||||
|
@ -33,15 +33,15 @@ class UploadQuoteRequest extends Request
|
||||
$rules = [];
|
||||
|
||||
if ($this->file('documents') && is_array($this->file('documents'))) {
|
||||
$rules['documents.*'] = $this->file_validation;
|
||||
$rules['documents.*'] = $this->fileValidation();
|
||||
} elseif ($this->file('documents')) {
|
||||
$rules['documents'] = $this->file_validation;
|
||||
$rules['documents'] = $this->fileValidation();
|
||||
}
|
||||
|
||||
if ($this->file('file') && is_array($this->file('file'))) {
|
||||
$rules['file.*'] = $this->file_validation;
|
||||
$rules['file.*'] = $this->fileValidation();
|
||||
} elseif ($this->file('file')) {
|
||||
$rules['file'] = $this->file_validation;
|
||||
$rules['file'] = $this->fileValidation();
|
||||
}
|
||||
|
||||
$rules['is_public'] = 'sometimes|boolean';
|
||||
|
@ -57,15 +57,15 @@ class StoreRecurringExpenseRequest extends Request
|
||||
$rules['currency_id'] = 'bail|required|integer|exists:currencies,id';
|
||||
|
||||
if ($this->file('documents') && is_array($this->file('documents'))) {
|
||||
$rules['documents.*'] = $this->file_validation;
|
||||
$rules['documents.*'] = $this->fileValidation();
|
||||
} elseif ($this->file('documents')) {
|
||||
$rules['documents'] = $this->file_validation;
|
||||
$rules['documents'] = $this->fileValidation();
|
||||
}
|
||||
|
||||
if ($this->file('file') && is_array($this->file('file'))) {
|
||||
$rules['file.*'] = $this->file_validation;
|
||||
$rules['file.*'] = $this->fileValidation();
|
||||
} elseif ($this->file('file')) {
|
||||
$rules['file'] = $this->file_validation;
|
||||
$rules['file'] = $this->fileValidation();
|
||||
}
|
||||
|
||||
return $this->globalRules($rules);
|
||||
|
@ -49,15 +49,15 @@ class UpdateRecurringExpenseRequest extends Request
|
||||
$rules['category_id'] = 'bail|nullable|sometimes|exists:expense_categories,id,company_id,'.auth()->user()->company()->id.',is_deleted,0';
|
||||
|
||||
if ($this->file('documents') && is_array($this->file('documents'))) {
|
||||
$rules['documents.*'] = $this->file_validation;
|
||||
$rules['documents.*'] = $this->fileValidation();
|
||||
} elseif ($this->file('documents')) {
|
||||
$rules['documents'] = $this->file_validation;
|
||||
$rules['documents'] = $this->fileValidation();
|
||||
}
|
||||
|
||||
if ($this->file('file') && is_array($this->file('file'))) {
|
||||
$rules['file.*'] = $this->file_validation;
|
||||
$rules['file.*'] = $this->fileValidation();
|
||||
} elseif ($this->file('file')) {
|
||||
$rules['file'] = $this->file_validation;
|
||||
$rules['file'] = $this->fileValidation();
|
||||
}
|
||||
|
||||
return $this->globalRules($rules);
|
||||
|
@ -30,15 +30,15 @@ class UploadRecurringExpenseRequest extends Request
|
||||
$rules = [];
|
||||
|
||||
if ($this->file('documents') && is_array($this->file('documents'))) {
|
||||
$rules['documents.*'] = $this->file_validation;
|
||||
$rules['documents.*'] = $this->fileValidation();
|
||||
} elseif ($this->file('documents')) {
|
||||
$rules['documents'] = $this->file_validation;
|
||||
$rules['documents'] = $this->fileValidation();
|
||||
}
|
||||
|
||||
if ($this->file('file') && is_array($this->file('file'))) {
|
||||
$rules['file.*'] = $this->file_validation;
|
||||
$rules['file.*'] = $this->fileValidation();
|
||||
} elseif ($this->file('file')) {
|
||||
$rules['file'] = $this->file_validation;
|
||||
$rules['file'] = $this->fileValidation();
|
||||
}
|
||||
|
||||
return $rules;
|
||||
|
@ -46,17 +46,17 @@ class StoreRecurringInvoiceRequest extends Request
|
||||
$rules = [];
|
||||
|
||||
if ($this->file('documents') && is_array($this->file('documents'))) {
|
||||
$rules['documents.*'] = $this->file_validation;
|
||||
$rules['documents.*'] = $this->fileValidation();
|
||||
} elseif ($this->file('documents')) {
|
||||
$rules['documents'] = $this->file_validation;
|
||||
$rules['documents'] = $this->fileValidation();
|
||||
}else {
|
||||
$rules['documents'] = 'bail|sometimes|array';
|
||||
}
|
||||
|
||||
if ($this->file('file') && is_array($this->file('file'))) {
|
||||
$rules['file.*'] = $this->file_validation;
|
||||
$rules['file.*'] = $this->fileValidation();
|
||||
} elseif ($this->file('file')) {
|
||||
$rules['file'] = $this->file_validation;
|
||||
$rules['file'] = $this->fileValidation();
|
||||
}
|
||||
|
||||
$rules['client_id'] = 'required|exists:clients,id,company_id,'.$user->company()->id;
|
||||
|
@ -45,17 +45,17 @@ class UpdateRecurringInvoiceRequest extends Request
|
||||
$rules = [];
|
||||
|
||||
if ($this->file('documents') && is_array($this->file('documents'))) {
|
||||
$rules['documents.*'] = $this->file_validation;
|
||||
$rules['documents.*'] = $this->fileValidation();
|
||||
} elseif ($this->file('documents')) {
|
||||
$rules['documents'] = $this->file_validation;
|
||||
$rules['documents'] = $this->fileValidation();
|
||||
}else {
|
||||
$rules['documents'] = 'bail|sometimes|array';
|
||||
}
|
||||
|
||||
if ($this->file('file') && is_array($this->file('file'))) {
|
||||
$rules['file.*'] = $this->file_validation;
|
||||
$rules['file.*'] = $this->fileValidation();
|
||||
} elseif ($this->file('file')) {
|
||||
$rules['file'] = $this->file_validation;
|
||||
$rules['file'] = $this->fileValidation();
|
||||
}
|
||||
|
||||
$rules['number'] = ['bail', 'sometimes', Rule::unique('recurring_invoices')->where('company_id', $user->company()->id)->ignore($this->recurring_invoice->id)];
|
||||
|
@ -33,15 +33,15 @@ class UploadRecurringInvoiceRequest extends Request
|
||||
$rules = [];
|
||||
|
||||
if ($this->file('documents') && is_array($this->file('documents'))) {
|
||||
$rules['documents.*'] = $this->file_validation;
|
||||
$rules['documents.*'] = $this->fileValidation();
|
||||
} elseif ($this->file('documents')) {
|
||||
$rules['documents'] = $this->file_validation;
|
||||
$rules['documents'] = $this->fileValidation();
|
||||
}
|
||||
|
||||
if ($this->file('file') && is_array($this->file('file'))) {
|
||||
$rules['file.*'] = $this->file_validation;
|
||||
$rules['file.*'] = $this->fileValidation();
|
||||
} elseif ($this->file('file')) {
|
||||
$rules['file'] = $this->file_validation;
|
||||
$rules['file'] = $this->fileValidation();
|
||||
}
|
||||
|
||||
$rules['is_public'] = 'sometimes|boolean';
|
||||
|
@ -46,15 +46,15 @@ class StoreRecurringQuoteRequest extends Request
|
||||
$rules = [];
|
||||
|
||||
if ($this->file('documents') && is_array($this->file('documents'))) {
|
||||
$rules['documents.*'] = $this->file_validation;
|
||||
$rules['documents.*'] = $this->fileValidation();
|
||||
} elseif ($this->file('documents')) {
|
||||
$rules['documents'] = $this->file_validation;
|
||||
$rules['documents'] = $this->fileValidation();
|
||||
}
|
||||
|
||||
if ($this->file('file') && is_array($this->file('file'))) {
|
||||
$rules['file.*'] = $this->file_validation;
|
||||
$rules['file.*'] = $this->fileValidation();
|
||||
} elseif ($this->file('file')) {
|
||||
$rules['file'] = $this->file_validation;
|
||||
$rules['file'] = $this->fileValidation();
|
||||
}
|
||||
|
||||
$rules['client_id'] = 'required|exists:clients,id,company_id,'.$user->company()->id;
|
||||
|
@ -38,15 +38,15 @@ class UpdateRecurringQuoteRequest extends Request
|
||||
$rules = [];
|
||||
|
||||
if ($this->file('documents') && is_array($this->file('documents'))) {
|
||||
$rules['documents.*'] = $this->file_validation;
|
||||
$rules['documents.*'] = $this->fileValidation();
|
||||
} elseif ($this->file('documents')) {
|
||||
$rules['documents'] = $this->file_validation;
|
||||
$rules['documents'] = $this->fileValidation();
|
||||
}
|
||||
|
||||
if ($this->file('file') && is_array($this->file('file'))) {
|
||||
$rules['file.*'] = $this->file_validation;
|
||||
$rules['file.*'] = $this->fileValidation();
|
||||
} elseif ($this->file('file')) {
|
||||
$rules['file'] = $this->file_validation;
|
||||
$rules['file'] = $this->fileValidation();
|
||||
}
|
||||
|
||||
if ($this->number) {
|
||||
|
@ -30,15 +30,15 @@ class UploadRecurringQuoteRequest extends Request
|
||||
$rules = [];
|
||||
|
||||
if ($this->file('documents') && is_array($this->file('documents'))) {
|
||||
$rules['documents.*'] = $this->file_validation;
|
||||
$rules['documents.*'] = $this->fileValidation();
|
||||
} elseif ($this->file('documents')) {
|
||||
$rules['documents'] = $this->file_validation;
|
||||
$rules['documents'] = $this->fileValidation();
|
||||
}
|
||||
|
||||
if ($this->file('file') && is_array($this->file('file'))) {
|
||||
$rules['file.*'] = $this->file_validation;
|
||||
$rules['file.*'] = $this->fileValidation();
|
||||
} elseif ($this->file('file')) {
|
||||
$rules['file'] = $this->file_validation;
|
||||
$rules['file'] = $this->fileValidation();
|
||||
}
|
||||
|
||||
return $rules;
|
||||
|
@ -20,7 +20,7 @@ class Request extends FormRequest
|
||||
use MakesHash;
|
||||
use RuntimeFormRequest;
|
||||
|
||||
protected $file_validation = 'sometimes|file|mimes:png,ai,jpeg,tiff,pdf,gif,psd,txt,doc,xls,ppt,xlsx,docx,pptx,webp,xml,zip,csv,ods,odt,odp|max:100000';
|
||||
protected $file_validation = 'sometimes|file|max:100000|mimes:png,ai,jpeg,tiff,pdf,gif,psd,txt,doc,xls,ppt,xlsx,docx,pptx,webp,xml,zip,csv,ods,odt,odp';
|
||||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
*
|
||||
@ -31,6 +31,15 @@ class Request extends FormRequest
|
||||
return [];
|
||||
}
|
||||
|
||||
public function fileValidation()
|
||||
{
|
||||
if(config('ninja.upload_extensions'))
|
||||
return $this->file_validation. ",".config('ninja.upload_extensions');
|
||||
|
||||
return $this->file_validation;
|
||||
|
||||
}
|
||||
|
||||
public function globalRules($rules)
|
||||
{
|
||||
$merge_rules = [];
|
||||
|
@ -79,17 +79,17 @@ class StoreTaskRequest extends Request
|
||||
}];
|
||||
|
||||
if ($this->file('documents') && is_array($this->file('documents'))) {
|
||||
$rules['documents.*'] = $this->file_validation;
|
||||
$rules['documents.*'] = $this->fileValidation();
|
||||
} elseif ($this->file('documents')) {
|
||||
$rules['documents'] = $this->file_validation;
|
||||
$rules['documents'] = $this->fileValidation();
|
||||
}else {
|
||||
$rules['documents'] = 'bail|sometimes|array';
|
||||
}
|
||||
|
||||
if ($this->file('file') && is_array($this->file('file'))) {
|
||||
$rules['file.*'] = $this->file_validation;
|
||||
$rules['file.*'] = $this->fileValidation();
|
||||
} elseif ($this->file('file')) {
|
||||
$rules['file'] = $this->file_validation;
|
||||
$rules['file'] = $this->fileValidation();
|
||||
}
|
||||
|
||||
|
||||
|
@ -85,17 +85,17 @@ class UpdateTaskRequest extends Request
|
||||
}];
|
||||
|
||||
if ($this->file('documents') && is_array($this->file('documents'))) {
|
||||
$rules['documents.*'] = $this->file_validation;
|
||||
$rules['documents.*'] = $this->fileValidation();
|
||||
} elseif ($this->file('documents')) {
|
||||
$rules['documents'] = $this->file_validation;
|
||||
$rules['documents'] = $this->fileValidation();
|
||||
}else {
|
||||
$rules['documents'] = 'bail|sometimes|array';
|
||||
}
|
||||
|
||||
if ($this->file('file') && is_array($this->file('file'))) {
|
||||
$rules['file.*'] = $this->file_validation;
|
||||
$rules['file.*'] = $this->fileValidation();
|
||||
} elseif ($this->file('file')) {
|
||||
$rules['file'] = $this->file_validation;
|
||||
$rules['file'] = $this->fileValidation();
|
||||
}
|
||||
|
||||
return $this->globalRules($rules);
|
||||
|
@ -33,15 +33,15 @@ class UploadTaskRequest extends Request
|
||||
$rules = [];
|
||||
|
||||
if ($this->file('documents') && is_array($this->file('documents'))) {
|
||||
$rules['documents.*'] = $this->file_validation;
|
||||
$rules['documents.*'] = $this->fileValidation();
|
||||
} elseif ($this->file('documents')) {
|
||||
$rules['documents'] = $this->file_validation;
|
||||
$rules['documents'] = $this->fileValidation();
|
||||
}
|
||||
|
||||
if ($this->file('file') && is_array($this->file('file'))) {
|
||||
$rules['file.*'] = $this->file_validation;
|
||||
$rules['file.*'] = $this->fileValidation();
|
||||
} elseif ($this->file('file')) {
|
||||
$rules['file'] = $this->file_validation;
|
||||
$rules['file'] = $this->fileValidation();
|
||||
}
|
||||
|
||||
$rules['is_public'] = 'sometimes|boolean';
|
||||
|
@ -61,17 +61,17 @@ class StoreVendorRequest extends Request
|
||||
$rules['currency_id'] = 'bail|required|exists:currencies,id';
|
||||
|
||||
if ($this->file('documents') && is_array($this->file('documents'))) {
|
||||
$rules['documents.*'] = $this->file_validation;
|
||||
$rules['documents.*'] = $this->fileValidation();
|
||||
} elseif ($this->file('documents')) {
|
||||
$rules['documents'] = $this->file_validation;
|
||||
$rules['documents'] = $this->fileValidation();
|
||||
}else {
|
||||
$rules['documents'] = 'bail|sometimes|array';
|
||||
}
|
||||
|
||||
if ($this->file('file') && is_array($this->file('file'))) {
|
||||
$rules['file.*'] = $this->file_validation;
|
||||
$rules['file.*'] = $this->fileValidation();
|
||||
} elseif ($this->file('file')) {
|
||||
$rules['file'] = $this->file_validation;
|
||||
$rules['file'] = $this->fileValidation();
|
||||
}
|
||||
|
||||
$rules['language_id'] = 'bail|nullable|sometimes|exists:languages,id';
|
||||
|
@ -62,17 +62,17 @@ class UpdateVendorRequest extends Request
|
||||
$rules['currency_id'] = 'bail|sometimes|exists:currencies,id';
|
||||
|
||||
if ($this->file('documents') && is_array($this->file('documents'))) {
|
||||
$rules['documents.*'] = $this->file_validation;
|
||||
$rules['documents.*'] = $this->fileValidation();
|
||||
} elseif ($this->file('documents')) {
|
||||
$rules['documents'] = $this->file_validation;
|
||||
$rules['documents'] = $this->fileValidation();
|
||||
}else {
|
||||
$rules['documents'] = 'bail|sometimes|array';
|
||||
}
|
||||
|
||||
if ($this->file('file') && is_array($this->file('file'))) {
|
||||
$rules['file.*'] = $this->file_validation;
|
||||
$rules['file.*'] = $this->fileValidation();
|
||||
} elseif ($this->file('file')) {
|
||||
$rules['file'] = $this->file_validation;
|
||||
$rules['file'] = $this->fileValidation();
|
||||
}
|
||||
|
||||
$rules['language_id'] = 'bail|nullable|sometimes|exists:languages,id';
|
||||
|
@ -30,15 +30,15 @@ class UploadVendorRequest extends Request
|
||||
$rules = [];
|
||||
|
||||
if ($this->file('documents') && is_array($this->file('documents'))) {
|
||||
$rules['documents.*'] = $this->file_validation;
|
||||
$rules['documents.*'] = $this->fileValidation();
|
||||
} elseif ($this->file('documents')) {
|
||||
$rules['documents'] = $this->file_validation;
|
||||
$rules['documents'] = $this->fileValidation();
|
||||
}
|
||||
|
||||
if ($this->file('file') && is_array($this->file('file'))) {
|
||||
$rules['file.*'] = $this->file_validation;
|
||||
$rules['file.*'] = $this->fileValidation();
|
||||
} elseif ($this->file('file')) {
|
||||
$rules['file'] = $this->file_validation;
|
||||
$rules['file'] = $this->fileValidation();
|
||||
}
|
||||
|
||||
$rules['is_public'] = 'sometimes|boolean';
|
||||
|
@ -5,7 +5,7 @@
|
||||
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||
*
|
||||
* @copyright Copyright (c) 2023. Invoice Ninja LLC (https://invoiceninja.com)
|
||||
*
|
||||
*1`
|
||||
* @license https://www.elastic.co/licensing/elastic-license
|
||||
*/
|
||||
|
||||
@ -21,6 +21,7 @@ class BlackListRule implements ValidationRule
|
||||
{
|
||||
/** Bad domains +/- dispoable email domains */
|
||||
private array $blacklist = [
|
||||
'wireconnected.com',
|
||||
'secure-coinspot.com',
|
||||
'casasotombo.com',
|
||||
'otpku.com',
|
||||
|
@ -57,9 +57,6 @@ class ValidRefundableRequest implements Rule
|
||||
|
||||
if ($payment->invoices()->exists()) {
|
||||
$this->checkInvoice($payment->invoices, $request_invoices);
|
||||
// foreach ($payment->invoices as $paymentable_invoice) {
|
||||
// $this->checkInvoice($paymentable_invoice, $request_invoices);
|
||||
// }
|
||||
}
|
||||
|
||||
foreach ($request_invoices as $request_invoice) {
|
||||
|
@ -61,7 +61,10 @@ class PaymentAppliedValidAmount implements Rule
|
||||
$payment_amounts = 0;
|
||||
$invoice_amounts = 0;
|
||||
|
||||
$payment_amounts = $payment->amount - $payment->refunded - $payment->applied;
|
||||
// $payment_amounts = $payment->amount - $payment->refunded - $payment->applied;
|
||||
|
||||
//20-03-2024 - applied amounts are never tainted by refunded amount.
|
||||
$payment_amounts = $payment->amount - $payment->applied;
|
||||
|
||||
if (request()->has('credits')
|
||||
&& is_array(request()->input('credits'))
|
||||
@ -84,10 +87,6 @@ class PaymentAppliedValidAmount implements Rule
|
||||
|
||||
$inv = $inv_collection->firstWhere('id', $invoice['invoice_id']);
|
||||
|
||||
nlog($inv->status_id);
|
||||
nlog($inv->amount);
|
||||
nlog($invoice['amount']);
|
||||
|
||||
if($inv->status_id == Invoice::STATUS_DRAFT && $inv->amount >= $invoice['amount']) {
|
||||
|
||||
} elseif ($inv->balance < $invoice['amount']) {
|
||||
|
@ -17,6 +17,7 @@ use Illuminate\Contracts\Validation\Rule;
|
||||
|
||||
/**
|
||||
* Class ValidCreditsPresentRule.
|
||||
* @deprecated 20-03-2024
|
||||
*/
|
||||
class ValidCreditsPresentRule implements Rule
|
||||
{
|
||||
@ -49,11 +50,8 @@ class ValidCreditsPresentRule implements Rule
|
||||
|
||||
private function validCreditsPresent(): bool
|
||||
{
|
||||
//todo need to ensure the clients credits are here not random ones!
|
||||
|
||||
if (array_key_exists('credits', $this->input) && is_array($this->input['credits']) && count($this->input['credits']) > 0) {
|
||||
$credit_collection = Credit::query()->whereIn('id', array_column($this->input['credits'], 'credit_id'))->count();
|
||||
|
||||
return $credit_collection == count($this->input['credits']);
|
||||
}
|
||||
|
||||
|
@ -85,6 +85,8 @@ class ProcessBankTransactionsNordigen implements ShouldQueue
|
||||
|
||||
$this->bank_integration->company->notification(new GenericNinjaAdminNotification($content))->ninja();
|
||||
|
||||
sleep(5);
|
||||
|
||||
throw $e;
|
||||
}
|
||||
if (!$this->nordigen_account) {
|
||||
|
492
app/Jobs/Brevo/ProcessBrevoWebhook.php
Normal file
492
app/Jobs/Brevo/ProcessBrevoWebhook.php
Normal file
@ -0,0 +1,492 @@
|
||||
<?php
|
||||
/**
|
||||
* Invoice Ninja (https://invoiceninja.com).
|
||||
*
|
||||
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||
*
|
||||
* @copyright Copyright (c) 2023. Invoice Ninja LLC (https://invoiceninja.com)
|
||||
*
|
||||
* @license https://www.elastic.co/licensing/elastic-license
|
||||
*/
|
||||
|
||||
namespace App\Jobs\Brevo;
|
||||
|
||||
use App\DataMapper\Analytics\Mail\EmailBounce;
|
||||
use App\DataMapper\Analytics\Mail\EmailSpam;
|
||||
use App\Jobs\Util\SystemLogger;
|
||||
use App\Libraries\MultiDB;
|
||||
use App\Models\Company;
|
||||
use App\Models\CreditInvitation;
|
||||
use App\Models\InvoiceInvitation;
|
||||
use App\Models\PurchaseOrderInvitation;
|
||||
use App\Models\QuoteInvitation;
|
||||
use App\Models\RecurringInvoiceInvitation;
|
||||
use App\Models\SystemLog;
|
||||
use App\Notifications\Ninja\EmailBounceNotification;
|
||||
use App\Notifications\Ninja\EmailSpamNotification;
|
||||
use Brevo\Client\Configuration;
|
||||
use Brevo\Client\Model\GetTransacEmailContentEvents;
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Foundation\Bus\Dispatchable;
|
||||
use Illuminate\Queue\InteractsWithQueue;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
use Brevo\Client\Api\TransactionalEmailsApi;
|
||||
use Turbo124\Beacon\Facades\LightLogs;
|
||||
|
||||
class ProcessBrevoWebhook implements ShouldQueue
|
||||
{
|
||||
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
|
||||
|
||||
public $tries = 1;
|
||||
|
||||
public $invitation;
|
||||
|
||||
private $entity;
|
||||
|
||||
private array $default_response = [
|
||||
'recipients' => '',
|
||||
'subject' => 'Message not found.',
|
||||
'entity' => '',
|
||||
'entity_id' => '',
|
||||
'events' => [],
|
||||
];
|
||||
|
||||
private ?Company $company = null;
|
||||
|
||||
/**
|
||||
* Create a new job instance.
|
||||
*
|
||||
*/
|
||||
public function __construct(private array $request)
|
||||
{
|
||||
}
|
||||
|
||||
private function getSystemLog(string $message_id): ?SystemLog
|
||||
{
|
||||
return SystemLog::query()
|
||||
->where('company_id', $this->invitation->company_id)
|
||||
->where('type_id', SystemLog::TYPE_WEBHOOK_RESPONSE)
|
||||
->whereJsonContains('log', ['message-id' => $message_id])
|
||||
->orderBy('id', 'desc')
|
||||
->first();
|
||||
|
||||
}
|
||||
|
||||
private function updateSystemLog(SystemLog $system_log, array $data): void
|
||||
{
|
||||
$system_log->log = $data;
|
||||
$system_log->save();
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the job.
|
||||
*
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
MultiDB::findAndSetDbByCompanyKey($this->request['tags'][0]);
|
||||
$this->company = Company::where('company_key', $this->request['tags'][0])->first();
|
||||
|
||||
$this->invitation = $this->discoverInvitation($this->request['message-id']);
|
||||
|
||||
if ($this->company && $this->request['event'] == 'spam' && config('ninja.notification.slack')) {
|
||||
$this->company->notification(new EmailSpamNotification($this->company))->ninja();
|
||||
}
|
||||
|
||||
if (!$this->invitation) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (array_key_exists('reason', $this->request)) {
|
||||
$this->invitation->email_error = $this->request['reason'];
|
||||
}
|
||||
|
||||
switch ($this->request['event']) {
|
||||
case 'delivered':
|
||||
return $this->processDelivery();
|
||||
case 'soft_bounce':
|
||||
case 'hard_bounce':
|
||||
case 'invalid_email':
|
||||
case 'blocked':
|
||||
|
||||
if ($this->request['subject'] == ctrans('texts.confirmation_subject')) {
|
||||
$this->company->notification(new EmailBounceNotification($this->request['email']))->ninja();
|
||||
}
|
||||
|
||||
return $this->processBounce();
|
||||
case 'spam':
|
||||
return $this->processSpamComplaint();
|
||||
case 'unique_opened':
|
||||
case 'opened':
|
||||
case 'click':
|
||||
return $this->processOpen();
|
||||
default:
|
||||
# code...
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// {
|
||||
// "id": 948562,
|
||||
// "email": "test@example.com",
|
||||
// "message-id": "<202312211546.94160606300@smtp-relay.mailin.fr>",
|
||||
// "date": "2023-12-21 18:34:42",
|
||||
// "tags": [
|
||||
// "gMtwiTIJtJxklXCj1OUFANgY6YYynQxV"
|
||||
// ],
|
||||
// "tag": "[\"gMtwiTIJtJxklXCj1OUFANgY6YYynQxV\"]",
|
||||
// "event": "unique_opened",
|
||||
// "subject": "Reminder: Invoice 0002 from Untitled Company",
|
||||
// "sending_ip": "74.125.208.8",
|
||||
// "ts": 1703180082,
|
||||
// "ts_epoch": 1703180082286,
|
||||
// "ts_event": 1703180082,
|
||||
// "link": "",
|
||||
// "sender_email": "user@example.com"
|
||||
// }
|
||||
// {
|
||||
// "id": 948562,
|
||||
// "email": "test@example.com",
|
||||
// "message-id": "<202312211555.14720890391@smtp-relay.mailin.fr>",
|
||||
// "date": "2023-12-21 18:34:53",
|
||||
// "tags": [
|
||||
// "gMtwiTIJtJxklXCj1OUFANgY6YYynQxV"
|
||||
// ],
|
||||
// "tag": "[\"gMtwiTIJtJxklXCj1OUFANgY6YYynQxV\"]",
|
||||
// "event": "opened",
|
||||
// "subject": "Reminder: Invoice 0002 from Untitled Company",
|
||||
// "sending_ip": "74.125.208.8",
|
||||
// "ts": 1703180093,
|
||||
// "ts_epoch": 1703180093075,
|
||||
// "ts_event": 1703180093,
|
||||
// "link": "",
|
||||
// "sender_email": "user@example.com"
|
||||
// }
|
||||
// {
|
||||
// "id": 948562,
|
||||
// "email": "paul@wer-ner.de",
|
||||
// "message-id": "<202312280812.10968711117@smtp-relay.mailin.fr>",
|
||||
// "date": "2023-12-28 09:20:18",
|
||||
// "tags": [
|
||||
// "gMtwiTIJtJxklXCj1OUFANgY6YYynQxV"
|
||||
// ],
|
||||
// "tag": "[\"gMtwiTIJtJxklXCj1OUFANgY6YYynQxV\"]",
|
||||
// "event": "click",
|
||||
// "subject": "Reminder: Invoice 0002 from Untitled Company",
|
||||
// "sending_ip": "79.235.133.157",
|
||||
// "ts": 1703751618,
|
||||
// "ts_epoch": 1703751618831,
|
||||
// "ts_event": 1703751618,
|
||||
// "link": "http://localhost/client/invoice/CssCvqOcKsenMCgYJ7EUNRZwxSDGUkau",
|
||||
// "sender_email": "user@example.com"
|
||||
// }
|
||||
|
||||
private function processOpen()
|
||||
{
|
||||
$this->invitation->opened_date = now();
|
||||
$this->invitation->save();
|
||||
|
||||
$data = array_merge($this->request, ['history' => $this->fetchMessage()]);
|
||||
|
||||
$sl = $this->getSystemLog($this->request['message-id']);
|
||||
|
||||
if ($sl) {
|
||||
$this->updateSystemLog($sl, $data);
|
||||
return;
|
||||
}
|
||||
|
||||
(
|
||||
new SystemLogger(
|
||||
$data,
|
||||
SystemLog::CATEGORY_MAIL,
|
||||
SystemLog::EVENT_MAIL_OPENED,
|
||||
SystemLog::TYPE_WEBHOOK_RESPONSE,
|
||||
$this->invitation->contact->client,
|
||||
$this->invitation->company
|
||||
)
|
||||
)->handle();
|
||||
}
|
||||
|
||||
// {
|
||||
// "id": 948562,
|
||||
// "email": "test@example",
|
||||
// "message-id": "<202312211742.12697514322@smtp-relay.mailin.fr>",
|
||||
// "date": "2023-12-21 18:42:31",
|
||||
// "tags": [
|
||||
// "gMtwiTIJtJxklXCj1OUFANgY6YYynQxV"
|
||||
// ],
|
||||
// "tag": "[\"gMtwiTIJtJxklXCj1OUFANgY6YYynQxV\"]",
|
||||
// "event": "delivered",
|
||||
// "subject": "Reminder: Invoice 0002 from Untitled Company",
|
||||
// "sending_ip": "77.32.148.26",
|
||||
// "ts_event": 1703180551,
|
||||
// "ts": 1703180551,
|
||||
// "reason": "sent",
|
||||
// "ts_epoch": 1703180551324,
|
||||
// "sender_email": "user@example.com"
|
||||
// }
|
||||
private function processDelivery()
|
||||
{
|
||||
$this->invitation->email_status = 'delivered';
|
||||
$this->invitation->save();
|
||||
|
||||
$data = array_merge($this->request, ['history' => $this->fetchMessage()]);
|
||||
|
||||
$sl = $this->getSystemLog($this->request['message-id']);
|
||||
|
||||
if ($sl) {
|
||||
$this->updateSystemLog($sl, $data);
|
||||
return;
|
||||
}
|
||||
|
||||
(
|
||||
new SystemLogger(
|
||||
$data,
|
||||
SystemLog::CATEGORY_MAIL,
|
||||
SystemLog::EVENT_MAIL_DELIVERY,
|
||||
SystemLog::TYPE_WEBHOOK_RESPONSE,
|
||||
$this->invitation->contact->client,
|
||||
$this->invitation->company
|
||||
)
|
||||
)->handle();
|
||||
}
|
||||
|
||||
// {
|
||||
// "id": 948562,
|
||||
// "email": "ryder36@example.net",
|
||||
// "message-id": "<202312211744.55168080257@smtp-relay.mailin.fr>",
|
||||
// "date": "2023-12-21 18:44:52",
|
||||
// "tags": [
|
||||
// "gMtwiTIJtJxklXCj1OUFANgY6YYynQxV"
|
||||
// ],
|
||||
// "tag": "[\"gMtwiTIJtJxklXCj1OUFANgY6YYynQxV\"]",
|
||||
// "event": "soft_bounce",
|
||||
// "subject": "Reminder: Invoice 0001 from Untitled Company",
|
||||
// "sending_ip": "77.32.148.26",
|
||||
// "ts_event": 1703180692,
|
||||
// "ts": 1703180692,
|
||||
// "reason": "Unable to find MX of domain example.net",
|
||||
// "ts_epoch": 1703180692382,
|
||||
// "sender_email": "user@example.com"
|
||||
// }
|
||||
// {
|
||||
// "id": 948562,
|
||||
// "email": "gloria46@example.com",
|
||||
// "message-id": "<202312211744.57456703957@smtp-relay.mailin.fr>",
|
||||
// "date": "2023-12-21 18:44:54",
|
||||
// "tags": [
|
||||
// "gMtwiTIJtJxklXCj1OUFANgY6YYynQxV"
|
||||
// ],
|
||||
// "tag": "[\"gMtwiTIJtJxklXCj1OUFANgY6YYynQxV\"]",
|
||||
// "event": "hard_bounce",
|
||||
// "subject": "Reminder: Invoice 0001 from Untitled Company",
|
||||
// "sending_ip": "77.32.148.25",
|
||||
// "ts_event": 1703180694,
|
||||
// "ts": 1703180694,
|
||||
// "reason": "blocked by Admin",
|
||||
// "ts_epoch": 1703180694175,
|
||||
// "sender_email": "user@example.com"
|
||||
// }
|
||||
// {
|
||||
// "event" : "invalid_email",
|
||||
// "email" : "example@example.com",
|
||||
// "id" : 1,
|
||||
// "date" : "yyyy-mm-dd hh:i:s",
|
||||
// "message-id" : "<xxx@msgid.domain>",
|
||||
// "subject" : "Test subject",
|
||||
// "tag" : "<defined-tag>",//json of array
|
||||
// "tags": [
|
||||
// "company_key"
|
||||
// ],
|
||||
// "sending_ip" : "xxx.xx.xxx.xx",
|
||||
// "ts_epoch" : 1534486682000,
|
||||
// "template_id" : 1,
|
||||
// "sender_email": "user@example.com",
|
||||
// }
|
||||
// {
|
||||
// "id": 948562,
|
||||
// "email": "neoma.langosh@example.com",
|
||||
// "message-id": "<202312211745.65538701430@smtp-relay.mailin.fr>",
|
||||
// "date": "2023-12-21 18:45:48",
|
||||
// "tags": [
|
||||
// "gMtwiTIJtJxklXCj1OUFANgY6YYynQxV"
|
||||
// ],
|
||||
// "tag": "[\"gMtwiTIJtJxklXCj1OUFANgY6YYynQxV\"]",
|
||||
// "event": "blocked",
|
||||
// "subject": "Reminder: Invoice 0001 from Untitled Company",
|
||||
// "ts_event": 1703180748,
|
||||
// "ts": 1703180748,
|
||||
// "reason": "blocked : due to blacklist user",
|
||||
// "ts_epoch": 1703180748987,
|
||||
// "sender_email": "user@example.com"
|
||||
// }
|
||||
|
||||
private function processBounce()
|
||||
{
|
||||
$this->invitation->email_status = 'bounced';
|
||||
$this->invitation->save();
|
||||
|
||||
$bounce = new EmailBounce(
|
||||
$this->request['tags'][0],
|
||||
$this->request['sender_email'], // TODO: @turbo124 is this the recipent?
|
||||
$this->request['message-id']
|
||||
);
|
||||
|
||||
LightLogs::create($bounce)->send();
|
||||
|
||||
$data = array_merge($this->request, ['history' => $this->fetchMessage()]);
|
||||
|
||||
$sl = $this->getSystemLog($this->request['message-id']);
|
||||
|
||||
if ($sl) {
|
||||
$this->updateSystemLog($sl, $data);
|
||||
return;
|
||||
}
|
||||
|
||||
(new SystemLogger($data, SystemLog::CATEGORY_MAIL, SystemLog::EVENT_MAIL_BOUNCED, SystemLog::TYPE_WEBHOOK_RESPONSE, $this->invitation->contact->client, $this->invitation->company))->handle();
|
||||
|
||||
// if(config('ninja.notification.slack'))
|
||||
// $this->invitation->company->notification(new EmailBounceNotification($this->invitation->company->account))->ninja();
|
||||
}
|
||||
|
||||
// {
|
||||
// "event" : "spam",
|
||||
// "email" : "example@example.com",
|
||||
// "id" : 1,
|
||||
// "date" : "yyyy-mm-dd hh:i:s",
|
||||
// "message-id" : "<xxx@msgid.domain>",
|
||||
// "tag" : "<defined-tag>",//json of array
|
||||
// "tags": [
|
||||
// "company_key"
|
||||
// ],
|
||||
// "sending_ip" : "xxx.xx.xxx.xx",
|
||||
// "sender_email": "user@example.com",
|
||||
// }
|
||||
private function processSpamComplaint()
|
||||
{
|
||||
$this->invitation->email_status = 'spam';
|
||||
$this->invitation->save();
|
||||
|
||||
$spam = new EmailSpam(
|
||||
$this->request['tags'][0],
|
||||
$this->request['sender_email'],
|
||||
$this->request['message-id']
|
||||
);
|
||||
|
||||
LightLogs::create($spam)->send();
|
||||
|
||||
$data = array_merge($this->request, ['history' => $this->fetchMessage()]);
|
||||
|
||||
$sl = $this->getSystemLog($this->request['message-id']);
|
||||
|
||||
if ($sl) {
|
||||
$this->updateSystemLog($sl, $data);
|
||||
return;
|
||||
}
|
||||
|
||||
(new SystemLogger($data, SystemLog::CATEGORY_MAIL, SystemLog::EVENT_MAIL_SPAM_COMPLAINT, SystemLog::TYPE_WEBHOOK_RESPONSE, $this->invitation->contact->client, $this->invitation->company))->handle();
|
||||
|
||||
if (config('ninja.notification.slack')) {
|
||||
$this->invitation->company->notification(new EmailSpamNotification($this->invitation->company->account))->ninja();
|
||||
}
|
||||
}
|
||||
|
||||
private function discoverInvitation(string $message_id)
|
||||
{
|
||||
$invitation = false;
|
||||
|
||||
if ($invitation = InvoiceInvitation::where('message_id', $message_id)->first()) {
|
||||
$this->entity = 'invoice';
|
||||
return $invitation;
|
||||
} elseif ($invitation = QuoteInvitation::where('message_id', $message_id)->first()) {
|
||||
$this->entity = 'quote';
|
||||
return $invitation;
|
||||
} elseif ($invitation = RecurringInvoiceInvitation::where('message_id', $message_id)->first()) {
|
||||
$this->entity = 'recurring_invoice';
|
||||
return $invitation;
|
||||
} elseif ($invitation = CreditInvitation::where('message_id', $message_id)->first()) {
|
||||
$this->entity = 'credit';
|
||||
return $invitation;
|
||||
} elseif ($invitation = PurchaseOrderInvitation::where('message_id', $message_id)->first()) {
|
||||
$this->entity = 'purchase_order';
|
||||
return $invitation;
|
||||
} else {
|
||||
return $invitation;
|
||||
}
|
||||
}
|
||||
|
||||
public function getRawMessage(string $message_id)
|
||||
{
|
||||
|
||||
$brevo_secret = !empty($this->company->settings->brevo_secret) ? $this->company->settings->brevo_secret : config('services.brevo.key');
|
||||
|
||||
$brevo = new TransactionalEmailsApi(null, Configuration::getDefaultConfiguration()->setApiKey('api-key', $brevo_secret));
|
||||
$messageDetail = $brevo->getTransacEmailContent($message_id);
|
||||
return $messageDetail;
|
||||
|
||||
}
|
||||
|
||||
|
||||
public function getBounceId(string $message_id): ?int
|
||||
{
|
||||
|
||||
$messageDetail = $this->getRawMessage($message_id);
|
||||
|
||||
$event = collect($messageDetail->getEvents())->first(function ($event) {
|
||||
|
||||
return $event?->Details?->BounceID ?? false;
|
||||
|
||||
});
|
||||
|
||||
return $event?->Details?->BounceID ?? null;
|
||||
|
||||
}
|
||||
|
||||
// TODO
|
||||
private function fetchMessage(): array
|
||||
{
|
||||
if (strlen($this->request['message-id']) < 1) {
|
||||
return $this->default_response;
|
||||
}
|
||||
|
||||
try {
|
||||
|
||||
$messageDetail = $this->getRawMessage($this->request['message-id']);
|
||||
|
||||
$recipient = array_key_exists("email", $this->request) ? $this->request["email"] : '';
|
||||
$server_ip = array_key_exists("sending_ip", $this->request) ? $this->request["sending_ip"] : '';
|
||||
$delivery_message = array_key_exists("reason", $this->request) ? $this->request["reason"] : '';
|
||||
$subject = $messageDetail->getSubject() ?? '';
|
||||
|
||||
$events = collect($messageDetail->getEvents())->map(function (GetTransacEmailContentEvents $event) use ($recipient, $server_ip, $delivery_message) { // @turbo124 event does only contain name & time property, how to handle transformation?!
|
||||
|
||||
return [
|
||||
'bounce_id' => '',
|
||||
'recipient' => $recipient,
|
||||
'status' => $event->name ?? '',
|
||||
'delivery_message' => $delivery_message, // TODO: @turbo124 this results in all cases for the history in the string, which may be incorrect
|
||||
'server' => '',
|
||||
'server_ip' => $server_ip,
|
||||
'date' => \Carbon\Carbon::parse($event->getTime())->format('Y-m-d H:i:s') ?? '',
|
||||
];
|
||||
|
||||
})->toArray();
|
||||
|
||||
return [
|
||||
'recipients' => $recipient,
|
||||
'subject' => $subject,
|
||||
'entity' => $this->entity ?? '',
|
||||
'entity_id' => $this->invitation->{$this->entity}->hashed_id ?? '',
|
||||
'events' => $events,
|
||||
];
|
||||
|
||||
} catch (\Exception $e) {
|
||||
|
||||
return $this->default_response;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
@ -63,11 +63,14 @@ class UpdateCalculatedFields
|
||||
Project::query()->with('tasks')->whereHas('tasks', function ($query) {
|
||||
$query->where('updated_at', '>', now()->subHours(2));
|
||||
})
|
||||
->cursor()
|
||||
->each(function ($project) {
|
||||
$project->current_hours = $this->calculateDuration($project);
|
||||
$project->save();
|
||||
});
|
||||
->cursor()
|
||||
->each(function ($project) {
|
||||
$project->current_hours = $this->calculateDuration($project);
|
||||
$project->save();
|
||||
});
|
||||
|
||||
//Clean password resets table
|
||||
\DB::connection($db)->table('password_resets')->where('created_at', '<', now()->subHour())->delete();
|
||||
|
||||
}
|
||||
}
|
||||
|
139
app/Jobs/EDocument/CreateEDocument.php
Normal file
139
app/Jobs/EDocument/CreateEDocument.php
Normal file
@ -0,0 +1,139 @@
|
||||
<?php
|
||||
/**
|
||||
* Invoice Ninja (https://invoiceninja.com).
|
||||
*
|
||||
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||
*
|
||||
* @copyright Copyright (c) 2023. Invoice Ninja LLC (https://invoiceninja.com)
|
||||
*
|
||||
* @license https://www.elastic.co/licensing/elastic-license
|
||||
*/
|
||||
|
||||
namespace App\Jobs\EDocument;
|
||||
|
||||
use App\Utils\Ninja;
|
||||
use App\Models\Quote;
|
||||
use App\Models\Credit;
|
||||
use App\Models\Invoice;
|
||||
use App\Models\PurchaseOrder;
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Support\Facades\App;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
use Illuminate\Queue\InteractsWithQueue;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Foundation\Bus\Dispatchable;
|
||||
use horstoeko\zugferd\ZugferdDocumentBuilder;
|
||||
use App\Services\EDocument\Standards\OrderXDocument;
|
||||
use App\Services\EDocument\Standards\FacturaEInvoice;
|
||||
use App\Services\EDocument\Standards\ZugferdEDokument;
|
||||
|
||||
class CreateEDocument implements ShouldQueue
|
||||
{
|
||||
use Dispatchable;
|
||||
use InteractsWithQueue;
|
||||
use Queueable;
|
||||
use SerializesModels;
|
||||
|
||||
public $deleteWhenMissingModels = true;
|
||||
|
||||
public function __construct(private object $document, private bool $returnObject = false)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the job.
|
||||
*
|
||||
* @return string|ZugferdDocumentBuilder
|
||||
*/
|
||||
public function handle(): string|ZugferdDocumentBuilder
|
||||
{
|
||||
/* Forget the singleton*/
|
||||
App::forgetInstance('translator');
|
||||
|
||||
/* Init a new copy of the translator*/
|
||||
$t = app('translator');
|
||||
/* Set the locale*/
|
||||
$settings_entity = ($this->document instanceof PurchaseOrder) ? $this->document->vendor : $this->document->client;
|
||||
App::setLocale($settings_entity->locale());
|
||||
|
||||
/* Set customized translations _NOW_ */
|
||||
$t->replace(Ninja::transformTranslations($this->document->client->getMergedSettings()));
|
||||
|
||||
$e_document_type = strlen($settings_entity->getSetting('e_invoice_type')) > 2 ? $settings_entity->getSetting('e_invoice_type') : "XInvoice_3_0";
|
||||
$e_quote_type = strlen($settings_entity->getSetting('e_quote_type')) > 2 ? $settings_entity->getSetting('e_quote_type') : "OrderX_Extended";
|
||||
|
||||
if ($this->document instanceof Invoice){
|
||||
switch ($e_document_type) {
|
||||
case "EN16931":
|
||||
case "XInvoice_3_0":
|
||||
case "XInvoice_2_3":
|
||||
case "XInvoice_2_2":
|
||||
case "XInvoice_2_1":
|
||||
case "XInvoice_2_0":
|
||||
case "XInvoice_1_0":
|
||||
case "XInvoice-Extended":
|
||||
case "XInvoice-BasicWL":
|
||||
case "XInvoice-Basic":
|
||||
$zugferd = (new ZugferdEDokument($this->document))->run();
|
||||
|
||||
return $this->returnObject ? $zugferd->xdocument : $zugferd->getXml();
|
||||
case "Facturae_3.2":
|
||||
case "Facturae_3.2.1":
|
||||
case "Facturae_3.2.2":
|
||||
return (new FacturaEInvoice($this->document, str_replace("Facturae_", "", $e_document_type)))->run();
|
||||
default:
|
||||
|
||||
$zugferd = (new ZugferdEDokument($this->document))->run();
|
||||
|
||||
return $this->returnObject ? $zugferd : $zugferd->getXml();
|
||||
|
||||
}
|
||||
}
|
||||
elseif ($this->document instanceof Quote){
|
||||
switch ($e_quote_type){
|
||||
case "OrderX_Basic":
|
||||
case "OrderX_Comfort":
|
||||
case "OrderX_Extended":
|
||||
$orderx = (new OrderXDocument($this->document))->run();
|
||||
return $this->returnObject ? $orderx->orderxdocument : $orderx->getXml();
|
||||
default:
|
||||
$orderx = (new OrderXDocument($this->document))->run();
|
||||
return $this->returnObject ? $orderx->orderxdocument : $orderx->getXml();
|
||||
}
|
||||
}
|
||||
elseif ($this->document instanceof PurchaseOrder){
|
||||
switch ($e_quote_type){
|
||||
case "OrderX_Basic":
|
||||
case "OrderX_Comfort":
|
||||
case "OrderX_Extended":
|
||||
$orderx = (new OrderXDocument($this->document))->run();
|
||||
return $this->returnObject ? $orderx->orderxdocument : $orderx->getXml();
|
||||
default:
|
||||
$orderx = (new OrderXDocument($this->document))->run();
|
||||
return $this->returnObject ? $orderx->orderxdocument : $orderx->getXml();
|
||||
}
|
||||
}
|
||||
elseif ($this->document instanceof Credit) {
|
||||
switch ($e_document_type) {
|
||||
case "EN16931":
|
||||
case "XInvoice_3_0":
|
||||
case "XInvoice_2_3":
|
||||
case "XInvoice_2_2":
|
||||
case "XInvoice_2_1":
|
||||
case "XInvoice_2_0":
|
||||
case "XInvoice_1_0":
|
||||
case "XInvoice-Extended":
|
||||
case "XInvoice-BasicWL":
|
||||
case "XInvoice-Basic":
|
||||
$zugferd = (new ZugferdEDokument($this->document))->run();
|
||||
return $this->returnObject ? $zugferd->xdocument : $zugferd->getXml();
|
||||
default:
|
||||
$zugferd = (new ZugferdEDokument($this->document))->run();
|
||||
return $this->returnObject ? $zugferd : $zugferd->getXml();
|
||||
}
|
||||
}
|
||||
else{
|
||||
return "";
|
||||
}
|
||||
}
|
||||
}
|
@ -1,86 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* Invoice Ninja (https://invoiceninja.com).
|
||||
*
|
||||
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||
*
|
||||
* @copyright Copyright (c) 2023. Invoice Ninja LLC (https://invoiceninja.com)
|
||||
*
|
||||
* @license https://www.elastic.co/licensing/elastic-license
|
||||
*/
|
||||
|
||||
namespace App\Jobs\Invoice;
|
||||
|
||||
use App\Models\Invoice;
|
||||
use App\Services\Invoice\EInvoice\FacturaEInvoice;
|
||||
use App\Services\Invoice\EInvoice\ZugferdEInvoice;
|
||||
use App\Utils\Ninja;
|
||||
use horstoeko\zugferd\ZugferdDocumentBuilder;
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Foundation\Bus\Dispatchable;
|
||||
use Illuminate\Queue\InteractsWithQueue;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
use Illuminate\Support\Facades\App;
|
||||
|
||||
class CreateEInvoice implements ShouldQueue
|
||||
{
|
||||
use Dispatchable;
|
||||
use InteractsWithQueue;
|
||||
use Queueable;
|
||||
use SerializesModels;
|
||||
|
||||
public $deleteWhenMissingModels = true;
|
||||
|
||||
public function __construct(private Invoice $invoice, private bool $returnObject = false)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the job.
|
||||
*
|
||||
* @return string|ZugferdDocumentBuilder
|
||||
*/
|
||||
public function handle(): string|ZugferdDocumentBuilder
|
||||
{
|
||||
/* Forget the singleton*/
|
||||
App::forgetInstance('translator');
|
||||
|
||||
/* Init a new copy of the translator*/
|
||||
$t = app('translator');
|
||||
/* Set the locale*/
|
||||
App::setLocale($this->invoice->client->locale());
|
||||
|
||||
/* Set customized translations _NOW_ */
|
||||
$t->replace(Ninja::transformTranslations($this->invoice->client->getMergedSettings()));
|
||||
|
||||
$e_invoice_type = $this->invoice->client->getSetting('e_invoice_type');
|
||||
|
||||
switch ($e_invoice_type) {
|
||||
case "EN16931":
|
||||
case "XInvoice_3_0":
|
||||
case "XInvoice_2_3":
|
||||
case "XInvoice_2_2":
|
||||
case "XInvoice_2_1":
|
||||
case "XInvoice_2_0":
|
||||
case "XInvoice_1_0":
|
||||
case "XInvoice-Extended":
|
||||
case "XInvoice-BasicWL":
|
||||
case "XInvoice-Basic":
|
||||
$zugferd = (new ZugferdEInvoice($this->invoice))->run();
|
||||
|
||||
return $this->returnObject ? $zugferd->xrechnung : $zugferd->getXml();
|
||||
case "Facturae_3.2":
|
||||
case "Facturae_3.2.1":
|
||||
case "Facturae_3.2.2":
|
||||
return (new FacturaEInvoice($this->invoice, str_replace("Facturae_", "", $e_invoice_type)))->run();
|
||||
default:
|
||||
|
||||
$zugferd = (new ZugferdEInvoice($this->invoice))->run();
|
||||
|
||||
return $this->returnObject ? $zugferd : $zugferd->getXml();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@ -62,6 +62,7 @@ class NinjaMailerJob implements ShouldQueue
|
||||
|
||||
protected $client_mailgun_domain = false;
|
||||
|
||||
protected $client_brevo_secret = false;
|
||||
|
||||
public function __construct(public ?NinjaMailerObject $nmo, public bool $override = false)
|
||||
{
|
||||
@ -99,7 +100,7 @@ class NinjaMailerJob implements ShouldQueue
|
||||
}
|
||||
|
||||
$this->nmo->mailable->replyTo($this->nmo->settings->reply_to_email, $reply_to_name);
|
||||
} elseif(isset($this->nmo->invitation->user)) {
|
||||
} elseif (isset ($this->nmo->invitation->user)) {
|
||||
$this->nmo->mailable->replyTo($this->nmo->invitation->user->email, $this->nmo->invitation->user->present()->name());
|
||||
} else {
|
||||
$this->nmo->mailable->replyTo($this->company->owner()->email, $this->company->owner()->present()->name());
|
||||
@ -112,16 +113,16 @@ class NinjaMailerJob implements ShouldQueue
|
||||
/* If we have an invitation present, we pass the invitation key into the email headers*/
|
||||
if ($this->nmo->invitation) {
|
||||
$this->nmo
|
||||
->mailable
|
||||
->withSymfonyMessage(function ($message) {
|
||||
$message->getHeaders()->addTextHeader('x-invitation', $this->nmo->invitation->key);
|
||||
});
|
||||
->mailable
|
||||
->withSymfonyMessage(function ($message) {
|
||||
$message->getHeaders()->addTextHeader('x-invitation', $this->nmo->invitation->key);
|
||||
});
|
||||
}
|
||||
|
||||
//send email
|
||||
try {
|
||||
nlog("Trying to send to {$this->nmo->to_user->email} ". now()->toDateTimeString());
|
||||
nlog("Using mailer => ". $this->mailer);
|
||||
nlog("Trying to send to {$this->nmo->to_user->email} " . now()->toDateTimeString());
|
||||
nlog("Using mailer => " . $this->mailer);
|
||||
|
||||
$mailer = Mail::mailer($this->mailer);
|
||||
|
||||
@ -133,10 +134,14 @@ class NinjaMailerJob implements ShouldQueue
|
||||
$mailer->mailgun_config($this->client_mailgun_secret, $this->client_mailgun_domain, $this->nmo->settings->mailgun_endpoint);
|
||||
}
|
||||
|
||||
if ($this->client_brevo_secret) {
|
||||
$mailer->brevo_config($this->client_brevo_secret);
|
||||
}
|
||||
|
||||
$mailable = $this->nmo->mailable;
|
||||
|
||||
/** May need to re-build it here */
|
||||
if(Ninja::isHosted() && method_exists($mailable, 'build')) {
|
||||
if (Ninja::isHosted() && method_exists($mailable, 'build')) {
|
||||
$mailable->build();
|
||||
}
|
||||
|
||||
@ -149,15 +154,15 @@ class NinjaMailerJob implements ShouldQueue
|
||||
$this->incrementEmailCounter();
|
||||
|
||||
LightLogs::create(new EmailSuccess($this->nmo->company->company_key, $this->nmo->mailable->subject))
|
||||
->send();
|
||||
->send();
|
||||
|
||||
} catch(\Symfony\Component\Mime\Exception\RfcComplianceException $e) {
|
||||
} catch (\Symfony\Component\Mime\Exception\RfcComplianceException $e) {
|
||||
nlog("Mailer failed with a Logic Exception {$e->getMessage()}");
|
||||
$this->fail();
|
||||
$this->cleanUpMailers();
|
||||
$this->logMailError($e->getMessage(), $this->company->clients()->first());
|
||||
return;
|
||||
} catch(\Symfony\Component\Mime\Exception\LogicException $e) {
|
||||
} catch (\Symfony\Component\Mime\Exception\LogicException $e) {
|
||||
nlog("Mailer failed with a Logic Exception {$e->getMessage()}");
|
||||
$this->fail();
|
||||
$this->cleanUpMailers();
|
||||
@ -224,7 +229,7 @@ class NinjaMailerJob implements ShouldQueue
|
||||
|
||||
private function incrementEmailCounter(): void
|
||||
{
|
||||
if(in_array($this->mailer, ['default','mailgun']))
|
||||
if(in_array($this->mailer, ['default','mailgun','postmark']))
|
||||
Cache::increment("email_quota".$this->company->account->key);
|
||||
|
||||
}
|
||||
@ -273,7 +278,7 @@ class NinjaMailerJob implements ShouldQueue
|
||||
// return $this;
|
||||
// }
|
||||
|
||||
if(Ninja::isHosted() && $this->company->account->isPaid() && $this->nmo->settings->email_sending_method == 'default') {
|
||||
if (Ninja::isHosted() && $this->company->account->isPaid() && $this->nmo->settings->email_sending_method == 'default') {
|
||||
//check if outlook.
|
||||
|
||||
try {
|
||||
@ -281,7 +286,7 @@ class NinjaMailerJob implements ShouldQueue
|
||||
$domain = explode("@", $email)[1] ?? "";
|
||||
$dns = dns_get_record($domain, DNS_MX);
|
||||
$server = $dns[0]["target"];
|
||||
if(stripos($server, "outlook.com") !== false) {
|
||||
if (stripos($server, "outlook.com") !== false) {
|
||||
|
||||
$this->mailer = 'postmark';
|
||||
$this->client_postmark_secret = config('services.postmark-outlook.token');
|
||||
@ -293,13 +298,13 @@ class NinjaMailerJob implements ShouldQueue
|
||||
}
|
||||
|
||||
$this->nmo
|
||||
->mailable
|
||||
->from(config('services.postmark-outlook.from.address'), $email_from_name);
|
||||
->mailable
|
||||
->from(config('services.postmark-outlook.from.address'), $email_from_name);
|
||||
|
||||
return $this;
|
||||
}
|
||||
} catch(\Exception $e) {
|
||||
|
||||
} catch (\Exception $e) {
|
||||
|
||||
nlog("problem switching outlook driver - hosted");
|
||||
nlog($e->getMessage());
|
||||
}
|
||||
@ -331,6 +336,10 @@ class NinjaMailerJob implements ShouldQueue
|
||||
$this->mailer = 'mailgun';
|
||||
$this->setMailgunMailer();
|
||||
return $this;
|
||||
case 'client_brevo':
|
||||
$this->mailer = 'brevo';
|
||||
$this->setBrevoMailer();
|
||||
return $this;
|
||||
case 'smtp':
|
||||
$this->mailer = 'smtp';
|
||||
$this->configureSmtpMailer();
|
||||
@ -380,11 +389,11 @@ class NinjaMailerJob implements ShouldQueue
|
||||
}
|
||||
|
||||
$user = $this->resolveSendingUser();
|
||||
$sending_email = (isset($this->nmo->settings->custom_sending_email) && stripos($this->nmo->settings->custom_sending_email, "@")) ? $this->nmo->settings->custom_sending_email : $user->email;
|
||||
$sending_email = (isset ($this->nmo->settings->custom_sending_email) && stripos($this->nmo->settings->custom_sending_email, "@")) ? $this->nmo->settings->custom_sending_email : $user->email;
|
||||
|
||||
$this->nmo
|
||||
->mailable
|
||||
->from($sending_email, $email_from_name);
|
||||
->mailable
|
||||
->from($sending_email, $email_from_name);
|
||||
|
||||
}
|
||||
|
||||
@ -407,8 +416,8 @@ class NinjaMailerJob implements ShouldQueue
|
||||
|
||||
if (env($this->company->id . '_MAIL_FROM_ADDRESS')) {
|
||||
$this->nmo
|
||||
->mailable
|
||||
->from(env($this->company->id . '_MAIL_FROM_ADDRESS', env('MAIL_FROM_ADDRESS')), env($this->company->id . '_MAIL_FROM_NAME', env('MAIL_FROM_NAME')));
|
||||
->mailable
|
||||
->from(env($this->company->id . '_MAIL_FROM_ADDRESS', env('MAIL_FROM_ADDRESS')), env($this->company->id . '_MAIL_FROM_NAME', env('MAIL_FROM_NAME')));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -426,6 +435,8 @@ class NinjaMailerJob implements ShouldQueue
|
||||
|
||||
$this->client_mailgun_domain = false;
|
||||
|
||||
$this->client_brevo_secret = false;
|
||||
|
||||
//always dump the drivers to prevent reuse
|
||||
app('mail.manager')->forgetMailers();
|
||||
}
|
||||
@ -475,8 +486,8 @@ class NinjaMailerJob implements ShouldQueue
|
||||
}
|
||||
|
||||
$this->nmo
|
||||
->mailable
|
||||
->from(config('services.mailgun.from.address'), $email_from_name);
|
||||
->mailable
|
||||
->from(config('services.mailgun.from.address'), $email_from_name);
|
||||
|
||||
}
|
||||
|
||||
@ -496,12 +507,35 @@ class NinjaMailerJob implements ShouldQueue
|
||||
|
||||
$user = $this->resolveSendingUser();
|
||||
|
||||
$sending_email = (isset($this->nmo->settings->custom_sending_email) && stripos($this->nmo->settings->custom_sending_email, "@")) ? $this->nmo->settings->custom_sending_email : $user->email;
|
||||
$sending_user = (isset($this->nmo->settings->email_from_name) && strlen($this->nmo->settings->email_from_name) > 2) ? $this->nmo->settings->email_from_name : $user->name();
|
||||
$sending_email = (isset ($this->nmo->settings->custom_sending_email) && stripos($this->nmo->settings->custom_sending_email, "@")) ? $this->nmo->settings->custom_sending_email : $user->email;
|
||||
$sending_user = (isset ($this->nmo->settings->email_from_name) && strlen($this->nmo->settings->email_from_name) > 2) ? $this->nmo->settings->email_from_name : $user->name();
|
||||
|
||||
$this->nmo
|
||||
->mailable
|
||||
->from($sending_email, $sending_user);
|
||||
->mailable
|
||||
->from($sending_email, $sending_user);
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures Brevo using client supplied secret
|
||||
* as the Mailer
|
||||
*/
|
||||
private function setBrevoMailer()
|
||||
{
|
||||
if (strlen($this->nmo->settings->brevo_secret) > 2) {
|
||||
$this->client_brevo_secret = $this->nmo->settings->brevo_secret;
|
||||
} else {
|
||||
$this->nmo->settings->email_sending_method = 'default';
|
||||
return $this->setMailDriver();
|
||||
}
|
||||
|
||||
$user = $this->resolveSendingUser();
|
||||
|
||||
$sending_email = (isset ($this->nmo->settings->custom_sending_email) && stripos($this->nmo->settings->custom_sending_email, "@")) ? $this->nmo->settings->custom_sending_email : $user->email;
|
||||
$sending_user = (isset ($this->nmo->settings->email_from_name) && strlen($this->nmo->settings->email_from_name) > 2) ? $this->nmo->settings->email_from_name : $user->name();
|
||||
|
||||
$this->nmo
|
||||
->mailable
|
||||
->from($sending_email, $sending_user);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -519,12 +553,12 @@ class NinjaMailerJob implements ShouldQueue
|
||||
|
||||
$user = $this->resolveSendingUser();
|
||||
|
||||
$sending_email = (isset($this->nmo->settings->custom_sending_email) && stripos($this->nmo->settings->custom_sending_email, "@")) ? $this->nmo->settings->custom_sending_email : $user->email;
|
||||
$sending_user = (isset($this->nmo->settings->email_from_name) && strlen($this->nmo->settings->email_from_name) > 2) ? $this->nmo->settings->email_from_name : $user->name();
|
||||
$sending_email = (isset ($this->nmo->settings->custom_sending_email) && stripos($this->nmo->settings->custom_sending_email, "@")) ? $this->nmo->settings->custom_sending_email : $user->email;
|
||||
$sending_user = (isset ($this->nmo->settings->email_from_name) && strlen($this->nmo->settings->email_from_name) > 2) ? $this->nmo->settings->email_from_name : $user->name();
|
||||
|
||||
$this->nmo
|
||||
->mailable
|
||||
->from($sending_email, $sending_user);
|
||||
->mailable
|
||||
->from($sending_email, $sending_user);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -550,11 +584,11 @@ class NinjaMailerJob implements ShouldQueue
|
||||
}
|
||||
|
||||
$this->nmo
|
||||
->mailable
|
||||
->from($user->email, $user->name())
|
||||
->withSymfonyMessage(function ($message) use ($token) {
|
||||
$message->getHeaders()->addTextHeader('gmailtoken', $token);
|
||||
});
|
||||
->mailable
|
||||
->from($user->email, $user->name())
|
||||
->withSymfonyMessage(function ($message) use ($token) {
|
||||
$message->getHeaders()->addTextHeader('gmailtoken', $token);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
@ -578,7 +612,7 @@ class NinjaMailerJob implements ShouldQueue
|
||||
}
|
||||
|
||||
$google->getClient()->setAccessToken(json_encode($user->oauth_user_token));
|
||||
} catch(\Exception $e) {
|
||||
} catch (\Exception $e) {
|
||||
$this->logMailError('Gmail Token Invalid', $this->company->clients()->first());
|
||||
$this->nmo->settings->email_sending_method = 'default';
|
||||
return $this->setMailDriver();
|
||||
@ -598,7 +632,7 @@ class NinjaMailerJob implements ShouldQueue
|
||||
* Now that our token is refreshed and valid we can boot the
|
||||
* mail driver at runtime and also set the token which will persist
|
||||
* just for this request.
|
||||
*/
|
||||
*/
|
||||
|
||||
$token = $user->oauth_user_token->access_token;
|
||||
|
||||
@ -609,11 +643,11 @@ class NinjaMailerJob implements ShouldQueue
|
||||
}
|
||||
|
||||
$this->nmo
|
||||
->mailable
|
||||
->from($user->email, $user->name())
|
||||
->withSymfonyMessage(function ($message) use ($token) {
|
||||
$message->getHeaders()->addTextHeader('gmailtoken', $token);
|
||||
});
|
||||
->mailable
|
||||
->from($user->email, $user->name())
|
||||
->withSymfonyMessage(function ($message) use ($token) {
|
||||
$message->getHeaders()->addTextHeader('gmailtoken', $token);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
@ -626,7 +660,7 @@ class NinjaMailerJob implements ShouldQueue
|
||||
private function preFlightChecksFail(): bool
|
||||
{
|
||||
/* Always send regardless */
|
||||
if($this->override) {
|
||||
if ($this->override) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -646,7 +680,7 @@ class NinjaMailerJob implements ShouldQueue
|
||||
}
|
||||
|
||||
/* GMail users are uncapped */
|
||||
if (Ninja::isHosted() && (in_array($this->nmo->settings->email_sending_method, ['gmail', 'office365', 'client_postmark', 'client_mailgun']))) {
|
||||
if (Ninja::isHosted() && (in_array($this->nmo->settings->email_sending_method, ['gmail', 'office365', 'client_postmark', 'client_mailgun', 'client_brevo']))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -690,21 +724,23 @@ class NinjaMailerJob implements ShouldQueue
|
||||
*/
|
||||
private function logMailError($errors, $recipient_object): void
|
||||
{
|
||||
(new SystemLogger(
|
||||
$errors,
|
||||
SystemLog::CATEGORY_MAIL,
|
||||
SystemLog::EVENT_MAIL_SEND,
|
||||
SystemLog::TYPE_FAILURE,
|
||||
$recipient_object,
|
||||
$this->nmo->company
|
||||
))->handle();
|
||||
(
|
||||
new SystemLogger(
|
||||
$errors,
|
||||
SystemLog::CATEGORY_MAIL,
|
||||
SystemLog::EVENT_MAIL_SEND,
|
||||
SystemLog::TYPE_FAILURE,
|
||||
$recipient_object,
|
||||
$this->nmo->company
|
||||
)
|
||||
)->handle();
|
||||
|
||||
$job_failure = new EmailFailure($this->nmo->company->company_key);
|
||||
$job_failure->string_metric5 = 'failed_email';
|
||||
$job_failure->string_metric6 = substr($errors, 0, 150);
|
||||
|
||||
LightLogs::create($job_failure)
|
||||
->send();
|
||||
->send();
|
||||
|
||||
$job_failure = null;
|
||||
}
|
||||
@ -729,8 +765,8 @@ class NinjaMailerJob implements ShouldQueue
|
||||
|
||||
$token = json_decode($guzzle->post($url, [
|
||||
'form_params' => [
|
||||
'client_id' => config('ninja.o365.client_id') ,
|
||||
'client_secret' => config('ninja.o365.client_secret') ,
|
||||
'client_id' => config('ninja.o365.client_id'),
|
||||
'client_secret' => config('ninja.o365.client_secret'),
|
||||
'scope' => 'email Mail.Send offline_access profile User.Read openid',
|
||||
'grant_type' => 'refresh_token',
|
||||
'refresh_token' => $user->oauth_user_refresh_token
|
||||
|
@ -74,7 +74,7 @@ class BankTransactionSync implements ShouldQueue
|
||||
|
||||
if ($account->isEnterprisePaidClient()) {
|
||||
$account->bank_integrations()->where('integration_type', BankIntegration::INTEGRATION_TYPE_YODLEE)->where('auto_sync', true)->where('disabled_upstream', 0)->cursor()->each(function ($bank_integration) use ($account) {
|
||||
(new ProcessBankTransactionsYodlee($account->id, $bank_integration))->handle();
|
||||
(new ProcessBankTransactionsYodlee($account->bank_integration_account_id, $bank_integration))->handle();
|
||||
});
|
||||
}
|
||||
|
||||
@ -90,7 +90,14 @@ class BankTransactionSync implements ShouldQueue
|
||||
|
||||
if ((Ninja::isSelfHost() || (Ninja::isHosted() && $account->isEnterprisePaidClient()))) {
|
||||
$account->bank_integrations()->where('integration_type', BankIntegration::INTEGRATION_TYPE_NORDIGEN)->where('auto_sync', true)->where('disabled_upstream', 0)->cursor()->each(function ($bank_integration) {
|
||||
(new ProcessBankTransactionsNordigen($bank_integration))->handle();
|
||||
try {
|
||||
(new ProcessBankTransactionsNordigen($bank_integration))->handle();
|
||||
}
|
||||
catch(\Exception $e) {
|
||||
sleep(20);
|
||||
}
|
||||
|
||||
sleep(5);
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -45,7 +45,7 @@ class ProcessPostmarkWebhook implements ShouldQueue
|
||||
|
||||
private $entity;
|
||||
|
||||
private array $default_response = [
|
||||
private array $default_response = [
|
||||
'recipients' => '',
|
||||
'subject' => 'Message not found.',
|
||||
'entity' => '',
|
||||
@ -53,6 +53,8 @@ class ProcessPostmarkWebhook implements ShouldQueue
|
||||
'events' => [],
|
||||
];
|
||||
|
||||
private ?Company $company = null;
|
||||
|
||||
/**
|
||||
* Create a new job instance.
|
||||
*
|
||||
@ -64,11 +66,11 @@ class ProcessPostmarkWebhook implements ShouldQueue
|
||||
private function getSystemLog(string $message_id): ?SystemLog
|
||||
{
|
||||
return SystemLog::query()
|
||||
->where('company_id', $this->invitation->company_id)
|
||||
->where('type_id', SystemLog::TYPE_WEBHOOK_RESPONSE)
|
||||
->whereJsonContains('log', ['MessageID' => $message_id])
|
||||
->orderBy('id', 'desc')
|
||||
->first();
|
||||
->where('company_id', $this->invitation->company_id)
|
||||
->where('type_id', SystemLog::TYPE_WEBHOOK_RESPONSE)
|
||||
->whereJsonContains('log', ['MessageID' => $message_id])
|
||||
->orderBy('id', 'desc')
|
||||
->first();
|
||||
|
||||
}
|
||||
|
||||
@ -87,12 +89,12 @@ class ProcessPostmarkWebhook implements ShouldQueue
|
||||
public function handle()
|
||||
{
|
||||
MultiDB::findAndSetDbByCompanyKey($this->request['Tag']);
|
||||
$company = Company::where('company_key', $this->request['Tag'])->first();
|
||||
$this->company = Company::where('company_key', $this->request['Tag'])->first();
|
||||
|
||||
$this->invitation = $this->discoverInvitation($this->request['MessageID']);
|
||||
|
||||
if ($company && $this->request['RecordType'] == 'SpamComplaint' && config('ninja.notification.slack')) {
|
||||
$company->notification(new EmailSpamNotification($company))->ninja();
|
||||
if ($this->company && $this->request['RecordType'] == 'SpamComplaint' && config('ninja.notification.slack')) {
|
||||
$this->company->notification(new EmailSpamNotification($this->company))->ninja();
|
||||
}
|
||||
|
||||
if (!$this->invitation) {
|
||||
@ -108,8 +110,8 @@ class ProcessPostmarkWebhook implements ShouldQueue
|
||||
return $this->processDelivery();
|
||||
case 'Bounce':
|
||||
|
||||
if($this->request['Subject'] == ctrans('texts.confirmation_subject')) {
|
||||
$company->notification(new EmailBounceNotification($this->request['Email']))->ninja();
|
||||
if ($this->request['Subject'] == ctrans('texts.confirmation_subject')) {
|
||||
$this->company->notification(new EmailBounceNotification($this->request['Email']))->ninja();
|
||||
}
|
||||
|
||||
return $this->processBounce();
|
||||
@ -169,19 +171,21 @@ class ProcessPostmarkWebhook implements ShouldQueue
|
||||
|
||||
$sl = $this->getSystemLog($this->request['MessageID']);
|
||||
|
||||
if($sl) {
|
||||
if ($sl) {
|
||||
$this->updateSystemLog($sl, $data);
|
||||
return;
|
||||
}
|
||||
|
||||
(new SystemLogger(
|
||||
$data,
|
||||
SystemLog::CATEGORY_MAIL,
|
||||
SystemLog::EVENT_MAIL_OPENED,
|
||||
SystemLog::TYPE_WEBHOOK_RESPONSE,
|
||||
$this->invitation->contact->client,
|
||||
$this->invitation->company
|
||||
))->handle();
|
||||
(
|
||||
new SystemLogger(
|
||||
$data,
|
||||
SystemLog::CATEGORY_MAIL,
|
||||
SystemLog::EVENT_MAIL_OPENED,
|
||||
SystemLog::TYPE_WEBHOOK_RESPONSE,
|
||||
$this->invitation->contact->client,
|
||||
$this->invitation->company
|
||||
)
|
||||
)->handle();
|
||||
}
|
||||
|
||||
// {
|
||||
@ -207,19 +211,21 @@ class ProcessPostmarkWebhook implements ShouldQueue
|
||||
|
||||
$sl = $this->getSystemLog($this->request['MessageID']);
|
||||
|
||||
if($sl) {
|
||||
if ($sl) {
|
||||
$this->updateSystemLog($sl, $data);
|
||||
return;
|
||||
}
|
||||
|
||||
(new SystemLogger(
|
||||
$data,
|
||||
SystemLog::CATEGORY_MAIL,
|
||||
SystemLog::EVENT_MAIL_DELIVERY,
|
||||
SystemLog::TYPE_WEBHOOK_RESPONSE,
|
||||
$this->invitation->contact->client,
|
||||
$this->invitation->company
|
||||
))->handle();
|
||||
(
|
||||
new SystemLogger(
|
||||
$data,
|
||||
SystemLog::CATEGORY_MAIL,
|
||||
SystemLog::EVENT_MAIL_DELIVERY,
|
||||
SystemLog::TYPE_WEBHOOK_RESPONSE,
|
||||
$this->invitation->contact->client,
|
||||
$this->invitation->company
|
||||
)
|
||||
)->handle();
|
||||
}
|
||||
|
||||
// {
|
||||
@ -265,7 +271,7 @@ class ProcessPostmarkWebhook implements ShouldQueue
|
||||
|
||||
$sl = $this->getSystemLog($this->request['MessageID']);
|
||||
|
||||
if($sl) {
|
||||
if ($sl) {
|
||||
$this->updateSystemLog($sl, $data);
|
||||
return;
|
||||
}
|
||||
@ -316,7 +322,7 @@ class ProcessPostmarkWebhook implements ShouldQueue
|
||||
|
||||
$sl = $this->getSystemLog($this->request['MessageID']);
|
||||
|
||||
if($sl) {
|
||||
if ($sl) {
|
||||
$this->updateSystemLog($sl, $data);
|
||||
}
|
||||
|
||||
@ -349,7 +355,9 @@ class ProcessPostmarkWebhook implements ShouldQueue
|
||||
public function getRawMessage(string $message_id)
|
||||
{
|
||||
|
||||
$postmark = new PostmarkClient(config('services.postmark.token'));
|
||||
$postmark_secret = !empty($this->company->settings->postmark_secret) ? $this->company->settings->postmark_secret : config('services.postmark.token');
|
||||
|
||||
$postmark = new PostmarkClient($postmark_secret);
|
||||
$messageDetail = $postmark->getOutboundMessageDetails($message_id);
|
||||
return $messageDetail;
|
||||
|
||||
@ -362,7 +370,7 @@ class ProcessPostmarkWebhook implements ShouldQueue
|
||||
$messageDetail = $this->getRawMessage($message_id);
|
||||
|
||||
|
||||
$event = collect($messageDetail->messageevents)->first(function ($event) {
|
||||
$event = collect($messageDetail->messageevents)->first(function ($event) {
|
||||
|
||||
return $event?->Details?->BounceID ?? false;
|
||||
|
||||
@ -374,29 +382,31 @@ class ProcessPostmarkWebhook implements ShouldQueue
|
||||
|
||||
private function fetchMessage(): array
|
||||
{
|
||||
if(strlen($this->request['MessageID']) < 1) {
|
||||
if (strlen($this->request['MessageID']) < 1) {
|
||||
return $this->default_response;
|
||||
}
|
||||
|
||||
try {
|
||||
|
||||
$postmark = new PostmarkClient(config('services.postmark.token'));
|
||||
$postmark_secret = !empty($this->company->settings->postmark_secret) ? $this->company->settings->postmark_secret : config('services.postmark.token');
|
||||
|
||||
$postmark = new PostmarkClient($postmark_secret);
|
||||
$messageDetail = $postmark->getOutboundMessageDetails($this->request['MessageID']);
|
||||
|
||||
$recipients = collect($messageDetail['recipients'])->flatten()->implode(',');
|
||||
$subject = $messageDetail->subject ?? '';
|
||||
|
||||
$events = collect($messageDetail->messageevents)->map(function ($event) {
|
||||
$events = collect($messageDetail->messageevents)->map(function ($event) {
|
||||
|
||||
return [
|
||||
'bounce_id' => $event?->Details?->BounceID ?? '',
|
||||
'recipient' => $event->Recipient ?? '',
|
||||
'status' => $event->Type ?? '',
|
||||
'delivery_message' => $event->Details->DeliveryMessage ?? $event->Details->Summary ?? '',
|
||||
'server' => $event->Details->DestinationServer ?? '',
|
||||
'server_ip' => $event->Details->DestinationIP ?? '',
|
||||
'date' => \Carbon\Carbon::parse($event->ReceivedAt)->format('Y-m-d H:i:s') ?? '',
|
||||
];
|
||||
'bounce_id' => $event?->Details?->BounceID ?? '',
|
||||
'recipient' => $event->Recipient ?? '',
|
||||
'status' => $event->Type ?? '',
|
||||
'delivery_message' => $event->Details->DeliveryMessage ?? $event->Details->Summary ?? '',
|
||||
'server' => $event->Details->DestinationServer ?? '',
|
||||
'server_ip' => $event->Details->DestinationIP ?? '',
|
||||
'date' => \Carbon\Carbon::parse($event->ReceivedAt)->format('Y-m-d H:i:s') ?? '',
|
||||
];
|
||||
|
||||
})->toArray();
|
||||
|
||||
|
@ -67,6 +67,11 @@ class ZipPurchaseOrders implements ShouldQueue
|
||||
try {
|
||||
foreach ($invitations as $invitation) {
|
||||
|
||||
if ($invitation->purchase_order->vendor->getSetting("enable_e_invoice")) {
|
||||
$xml = $invitation->purchase_order->service()->getEInvoice();
|
||||
$zipFile->addFromString($invitation->purchase_order->getFileName("xml"), $xml);
|
||||
}
|
||||
|
||||
$file = (new CreateRawPdf($invitation))->handle();
|
||||
|
||||
$zipFile->addFromString($invitation->purchase_order->numberFormatter().".pdf", $file);
|
||||
|
@ -63,6 +63,10 @@ class ZipQuotes implements ShouldQueue
|
||||
try {
|
||||
|
||||
foreach ($invitations as $invitation) {
|
||||
if ($invitation->quote->client->getSetting('enable_e_invoice')) {
|
||||
$xml = $invitation->quote->service()->getEInvoice();
|
||||
$zipFile->addFromString($invitation->quote->getFileName("xml"), $xml);
|
||||
}
|
||||
$file = (new \App\Jobs\Entity\CreateRawPdf($invitation))->handle();
|
||||
$zipFile->addFromString($invitation->quote->numberFormatter() . '.pdf', $file);
|
||||
}
|
||||
|
@ -76,12 +76,12 @@ class SendRecurring implements ShouldQueue
|
||||
$invoice = $invoice->service()
|
||||
->markSent()
|
||||
->applyNumber()
|
||||
->fillDefaults()
|
||||
->fillDefaults(true)
|
||||
->adjustInventory()
|
||||
->save();
|
||||
} else {
|
||||
$invoice = $invoice->service()
|
||||
->fillDefaults()
|
||||
->fillDefaults(true)
|
||||
->save();
|
||||
}
|
||||
|
||||
|
@ -21,6 +21,7 @@ use Illuminate\Support\Str;
|
||||
use App\Models\CompanyToken;
|
||||
use App\Models\ClientContact;
|
||||
use App\Models\VendorContact;
|
||||
use App\DataProviders\SMSNumbers;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
/**
|
||||
@ -537,6 +538,10 @@ class MultiDB
|
||||
|
||||
$current_db = config('database.default');
|
||||
|
||||
if(SMSNumbers::hasNumber($phone)){
|
||||
return true;
|
||||
}
|
||||
|
||||
foreach (self::$dbs as $db) {
|
||||
self::setDB($db);
|
||||
if ($exists = Account::where('account_sms_verification_number', $phone)->where('account_sms_verified', true)->exists()) {
|
||||
|
@ -12,7 +12,7 @@
|
||||
|
||||
namespace App\Livewire;
|
||||
|
||||
use App\Jobs\Invoice\CreateEInvoice;
|
||||
use App\Jobs\EDocument\CreateEDocument;
|
||||
use App\Libraries\MultiDB;
|
||||
use App\Models\CreditInvitation;
|
||||
use App\Models\InvoiceInvitation;
|
||||
@ -113,7 +113,7 @@ class PdfSlot extends Component
|
||||
|
||||
$file_name = $this->entity->numberFormatter().'.xml';
|
||||
|
||||
$file = (new CreateEInvoice($this->entity))->handle();
|
||||
$file = (new CreateEDocument($this->entity))->handle();
|
||||
|
||||
$headers = ['Content-Type' => 'application/xml'];
|
||||
|
||||
|
@ -223,8 +223,11 @@ class RequiredClientInfo extends Component
|
||||
$this->show_form = true;
|
||||
|
||||
$hash = Cache::get(request()->input('hash'));
|
||||
|
||||
/** @var \App\Models\Invoice $invoice */
|
||||
$invoice = Invoice::find($this->decodePrimaryKey($hash['invoice_id']));
|
||||
|
||||
$this->invoice_terms = Invoice::find($this->decodePrimaryKey($hash['invoice_id']))->terms;
|
||||
$this->invoice_terms = $invoice->terms;
|
||||
}
|
||||
|
||||
count($this->fields) > 0 || $this->show_terms
|
||||
|
@ -140,7 +140,7 @@ class TemplateEmail extends Mailable
|
||||
'whitelabel' => $this->client->user->account->isPaid() ? true : false,
|
||||
'logo' => $this->company->present()->logo($settings),
|
||||
'links' => $this->build_email->getAttachmentLinks(),
|
||||
'email_preferences' => (Ninja::isHosted() && in_array($settings->email_sending_method, ['default', 'mailgun'])) ? $this->company->domain() . URL::signedRoute('client.email_preferences', ['entity' => $this->invitation->getEntityString(), 'invitation_key' => $this->invitation->key], absolute: false) : false,
|
||||
'email_preferences' => (Ninja::isHosted() && $this->invitation && in_array($settings->email_sending_method, ['default', 'mailgun'])) ? $this->company->domain() . URL::signedRoute('client.email_preferences', ['entity' => $this->invitation->getEntityString(), 'invitation_key' => $this->invitation->key], absolute: false) : false,
|
||||
]);
|
||||
|
||||
foreach ($this->build_email->getAttachments() as $file) {
|
||||
@ -159,15 +159,46 @@ class TemplateEmail extends Mailable
|
||||
}
|
||||
|
||||
}
|
||||
if ($this->invitation && $this->invitation->invoice && $this->invitation->invoice->client->getSetting('enable_e_invoice') && $this->company->account->hasFeature(Account::FEATURE_PDF_ATTACHMENT)) {
|
||||
$xml_string = $this->invitation->invoice->service()->getEInvoice($this->invitation->contact);
|
||||
if ($this->invitation->invoice) {
|
||||
if ($this->invitation && $this->invitation->invoice && $this->invitation->invoice->client->getSetting('enable_e_invoice') && $this->company->account->hasFeature(Account::FEATURE_PDF_ATTACHMENT)) {
|
||||
$xml_string = $this->invitation->invoice->service()->getEInvoice($this->invitation->contact);
|
||||
|
||||
if ($xml_string) {
|
||||
$this->attachData($xml_string, $this->invitation->invoice->getEFileName("xml"));
|
||||
}
|
||||
|
||||
if($xml_string) {
|
||||
$this->attachData($xml_string, $this->invitation->invoice->getEFileName("xml"));
|
||||
}
|
||||
|
||||
}
|
||||
elseif ($this->invitation->credit){
|
||||
if ($this->invitation && $this->invitation->credit && $this->invitation->credit->client->getSetting('enable_e_invoice') && $this->company->account->hasFeature(Account::FEATURE_PDF_ATTACHMENT)) {
|
||||
$xml_string = $this->invitation->credit->service()->getECredit($this->invitation->contact);
|
||||
|
||||
if ($xml_string) {
|
||||
$this->attachData($xml_string, $this->invitation->credit->getEFileName("xml"));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
elseif ($this->invitation->quote){
|
||||
if ($this->invitation && $this->invitation->quote && $this->invitation->quote->client->getSetting('enable_e_invoice') && $this->company->account->hasFeature(Account::FEATURE_PDF_ATTACHMENT)) {
|
||||
$xml_string = $this->invitation->quote->service()->getEQuote($this->invitation->contact);
|
||||
|
||||
if ($xml_string) {
|
||||
$this->attachData($xml_string, $this->invitation->quote->getEFileName("xml"));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
elseif ($this->invitation->purchase_order){
|
||||
if ($this->invitation && $this->invitation->purchase_order && $this->invitation->purchase_order->client->getSetting('enable_e_invoice') && $this->company->account->hasFeature(Account::FEATURE_PDF_ATTACHMENT)) {
|
||||
$xml_string = $this->invitation->purchase_order->service()->getEPurchaseOrder($this->invitation->contact);
|
||||
|
||||
if ($xml_string) {
|
||||
$this->attachData($xml_string, $this->invitation->purchase_order->getEFileName("xml"));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
|
@ -102,7 +102,7 @@ class Account extends BaseModel
|
||||
|
||||
private $free_plan_email_quota = 20;
|
||||
|
||||
private $paid_plan_email_quota = 400;
|
||||
private $paid_plan_email_quota = 300;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
@ -494,7 +494,7 @@ class Account extends BaseModel
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (Carbon::createFromTimestamp($this->created_at)->diffInWeeks() == 0) {
|
||||
if (Carbon::createFromTimestamp($this->created_at)->diffInWeeks() <= 1) {
|
||||
return 20;
|
||||
}
|
||||
|
||||
@ -503,11 +503,13 @@ class Account extends BaseModel
|
||||
}
|
||||
|
||||
if ($this->isPaid()) {
|
||||
$multiplier = $this->plan == 'enterprise' ? 2 : 1.2;
|
||||
|
||||
$limit = $this->paid_plan_email_quota;
|
||||
$limit += Carbon::createFromTimestamp($this->created_at)->diffInMonths() * 50;
|
||||
$limit += Carbon::createFromTimestamp($this->created_at)->diffInMonths() * (20 * $multiplier);
|
||||
} else {
|
||||
$limit = $this->free_plan_email_quota;
|
||||
$limit += Carbon::createFromTimestamp($this->created_at)->diffInMonths() * 2;
|
||||
$limit += Carbon::createFromTimestamp($this->created_at)->diffInMonths() * 1.5;
|
||||
}
|
||||
|
||||
return min($limit, 1000);
|
||||
|
@ -485,7 +485,7 @@ class Client extends BaseModel implements HasLocalePreference
|
||||
}
|
||||
|
||||
/*Company Settings*/
|
||||
elseif ((property_exists($this->company->settings, $setting) != false) && (isset($this->company->settings->{$setting}) !== false)) {
|
||||
elseif ((property_exists($this->company->settings, $setting) !== false) && (isset($this->company->settings->{$setting}) !== false)) {
|
||||
return $this->company->settings->{$setting};
|
||||
} elseif (property_exists(CompanySettings::defaults(), $setting)) {
|
||||
return CompanySettings::defaults()->{$setting};
|
||||
@ -754,7 +754,7 @@ class Client extends BaseModel implements HasLocalePreference
|
||||
|
||||
return $this->company->company_key.'/'.$this->client_hash.'/'.$contact_key.'/invoices/';
|
||||
}
|
||||
public function e_invoice_filepath($invitation): string
|
||||
public function e_document_filepath($invitation): string
|
||||
{
|
||||
$contact_key = $invitation->contact->contact_key;
|
||||
|
||||
|
@ -132,6 +132,7 @@ class CompanyGateway extends BaseModel
|
||||
// const TYPE_EWAY = 313;
|
||||
// const TYPE_FORTE = 314;
|
||||
// const PAYPAL_PPCP = 323;
|
||||
// const SQUARE = 320;
|
||||
|
||||
public $gateway_consts = [
|
||||
'38f2c48af60c7dd69e04248cbb24c36e' => 300,
|
||||
@ -144,7 +145,7 @@ class CompanyGateway extends BaseModel
|
||||
'8fdeed552015b3c7b44ed6c8ebd9e992' => 309,
|
||||
'd6814fc83f45d2935e7777071e629ef9' => 310,
|
||||
'bbd736b3254b0aabed6ad7fda1298c88' => 311,
|
||||
'1bd651fb213ca0c9d66ae3c336dc77e7' => 312,
|
||||
'1bd651fb213ca0c9d66ae3c336dc77e8' => 312,
|
||||
'944c20175bbe6b9972c05bcfe294c2c7' => 313,
|
||||
'kivcvjexxvdiyqtj3mju5d6yhpeht2xs' => 314,
|
||||
'65faab2ab6e3223dbe848b1686490baz' => 320,
|
||||
|
@ -202,7 +202,6 @@ class CompanyUser extends Pivot
|
||||
*/
|
||||
public function portalType(): bool
|
||||
{
|
||||
nlog(isset($this->react_settings->react_notification_link) && $this->react_settings->react_notification_link);
|
||||
return isset($this->react_settings->react_notification_link) && $this->react_settings->react_notification_link;
|
||||
}
|
||||
|
||||
|
@ -698,7 +698,7 @@ class RecurringInvoice extends BaseModel
|
||||
|
||||
public function subscription(): \Illuminate\Database\Eloquent\Relations\BelongsTo
|
||||
{
|
||||
return $this->belongsTo(Subscription::class);
|
||||
return $this->belongsTo(Subscription::class)->withTrashed();
|
||||
}
|
||||
|
||||
public function translate_entity()
|
||||
|
@ -12,6 +12,7 @@
|
||||
namespace App\Models;
|
||||
|
||||
use App\Utils\Traits\MakesHash;
|
||||
use Carbon\CarbonInterval;
|
||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
use Illuminate\Support\Carbon;
|
||||
|
||||
@ -248,6 +249,7 @@ class Task extends BaseModel
|
||||
$duration += max($end_time - $start_time, 0);
|
||||
}
|
||||
|
||||
// return CarbonInterval::seconds(round($duration))->locale($this->company->locale())->cascade()->forHumans();
|
||||
return round($duration);
|
||||
}
|
||||
|
||||
|
@ -226,6 +226,7 @@ class User extends Authenticatable implements MustVerifyEmail
|
||||
return $truth->getCompanyToken();
|
||||
}
|
||||
|
||||
// if (request()->header('X-API-TOKEN')) {
|
||||
if (request()->header('X-API-TOKEN')) {
|
||||
return CompanyToken::with(['cu'])->where('token', request()->header('X-API-TOKEN'))->first();
|
||||
}
|
||||
|
@ -41,6 +41,7 @@ use Laracasts\Presenter\PresentableTrait;
|
||||
* @property string|null $phone
|
||||
* @property string|null $private_notes
|
||||
* @property string|null $website
|
||||
* @property string|null $routing_id
|
||||
* @property bool $is_deleted
|
||||
* @property string|null $vat_number
|
||||
* @property string|null $transaction_name
|
||||
|
@ -193,6 +193,18 @@ class AuthorizePaymentDriver extends BaseDriver
|
||||
|
||||
public function import()
|
||||
{
|
||||
$this->init();
|
||||
|
||||
return (new AuthorizeCustomer($this))->importCustomers();
|
||||
}
|
||||
|
||||
public function importCustomers()
|
||||
{
|
||||
return $this->import();
|
||||
}
|
||||
|
||||
public function auth(): bool
|
||||
{
|
||||
return $this->init()->getPublicClientKey() ?? false;
|
||||
}
|
||||
}
|
||||
|
@ -579,15 +579,18 @@ class BaseDriver extends AbstractPaymentDriver
|
||||
$nmo->company = $this->client->company;
|
||||
$nmo->settings = $this->client->company->settings;
|
||||
|
||||
$invoices = Invoice::query()->whereIn('id', $this->transformKeys(array_column($this->payment_hash->invoices(), 'invoice_id')))->withTrashed()->get();
|
||||
|
||||
$invoices->first()->invitations->each(function ($invitation) use ($nmo) {
|
||||
if (! $invitation->contact->trashed()) {
|
||||
$nmo->to_user = $invitation->contact;
|
||||
NinjaMailerJob::dispatch($nmo);
|
||||
}
|
||||
});
|
||||
if($this->payment_hash)
|
||||
{
|
||||
$invoices = Invoice::query()->whereIn('id', $this->transformKeys(array_column($this->payment_hash->invoices(), 'invoice_id')))->withTrashed()->get();
|
||||
|
||||
$invoices->first()->invitations->each(function ($invitation) use ($nmo) {
|
||||
if (! $invitation->contact->trashed()) {
|
||||
$nmo->to_user = $invitation->contact;
|
||||
NinjaMailerJob::dispatch($nmo);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
$message = [
|
||||
'server_response' => $response,
|
||||
'data' => $this->payment_hash->data,
|
||||
@ -806,4 +809,14 @@ class BaseDriver extends AbstractPaymentDriver
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public function auth(): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public function importCustomers()
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -12,29 +12,40 @@
|
||||
|
||||
namespace App\PaymentDrivers;
|
||||
|
||||
use App\Jobs\Util\SystemLogger;
|
||||
use App\Models\ClientGatewayToken;
|
||||
use App\Models\GatewayType;
|
||||
use Exception;
|
||||
use App\Models\Client;
|
||||
use Braintree\Gateway;
|
||||
use App\Models\Invoice;
|
||||
use App\Models\Payment;
|
||||
use App\Models\SystemLog;
|
||||
use App\Models\GatewayType;
|
||||
use App\Models\PaymentHash;
|
||||
use App\Models\PaymentType;
|
||||
use App\Models\SystemLog;
|
||||
use App\Models\ClientContact;
|
||||
use App\Factory\ClientFactory;
|
||||
use Illuminate\Support\Carbon;
|
||||
use App\Jobs\Util\SystemLogger;
|
||||
use App\Models\ClientGatewayToken;
|
||||
use App\Factory\ClientContactFactory;
|
||||
use App\PaymentDrivers\Braintree\ACH;
|
||||
use App\PaymentDrivers\Braintree\CreditCard;
|
||||
use App\Utils\Traits\GeneratesCounter;
|
||||
use Illuminate\Database\QueryException;
|
||||
use App\PaymentDrivers\Braintree\PayPal;
|
||||
use Braintree\Gateway;
|
||||
use Exception;
|
||||
use Illuminate\Support\Facades\Validator;
|
||||
use App\PaymentDrivers\Braintree\CreditCard;
|
||||
|
||||
class BraintreePaymentDriver extends BaseDriver
|
||||
{
|
||||
use GeneratesCounter;
|
||||
|
||||
public $refundable = true;
|
||||
|
||||
public $token_billing = true;
|
||||
|
||||
public $can_authorise_credit_card = true;
|
||||
|
||||
private bool $completed = true;
|
||||
|
||||
/**
|
||||
* @var Gateway;
|
||||
*/
|
||||
@ -157,34 +168,6 @@ class BraintreePaymentDriver extends BaseDriver
|
||||
}
|
||||
}
|
||||
|
||||
// public function updateCustomer()
|
||||
// {
|
||||
// $customer = $this->findOrCreateCustomer();
|
||||
|
||||
// $result = $this->gateway->customer()->update(
|
||||
// $customer->id,
|
||||
// [
|
||||
// 'firstName' => $this->client->present()->name(),
|
||||
// 'email' => $this->client->present()->email(),
|
||||
// 'phone' => $this->client->present()->phone(),
|
||||
// 'creditCard' => [
|
||||
// 'billingAddress' => [
|
||||
// 'options' => [
|
||||
// 'updateExisting' => true
|
||||
// ],
|
||||
// 'firstName' => $this->client->present()->first_name() ?: $this->client->present()->name(),
|
||||
// 'lastName' => $this->client->present()->last_name() ?: '',
|
||||
// 'streetAddress' => $this->client->address1 ?: '',
|
||||
// 'extendedAddress' =>$this->client->address2 ?: '',
|
||||
// 'locality' => $this->client->city ?: '',
|
||||
// 'postalCode' => $this->client->postal_code ?: '',
|
||||
// 'countryCodeAlpha2' => $this->client->country ? $this->client->country->iso_3166_2 : 'US',
|
||||
// ],
|
||||
// ],
|
||||
// ]
|
||||
// );
|
||||
// }
|
||||
|
||||
public function refund(Payment $payment, $amount, $return_client_response = false)
|
||||
{
|
||||
$this->init();
|
||||
@ -324,13 +307,198 @@ class BraintreePaymentDriver extends BaseDriver
|
||||
|
||||
nlog('braintree webhook');
|
||||
|
||||
// if($webhookNotification)
|
||||
// nlog($webhookNotification->kind);
|
||||
|
||||
// // Example values for webhook notification properties
|
||||
// $message = $webhookNotification->kind; // "subscription_went_past_due"
|
||||
// $message = $webhookNotification->timestamp->format('D M j G:i:s T Y'); // "Sun Jan 1 00:00:00 UTC 2012"
|
||||
|
||||
return response()->json([], 200);
|
||||
}
|
||||
|
||||
public function auth(): bool
|
||||
{
|
||||
|
||||
try {
|
||||
$ct =$this->init()->gateway->clientToken()->generate();
|
||||
|
||||
return true;
|
||||
}
|
||||
catch(\Exception $e) {
|
||||
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private function find(string $customer_id = '') {
|
||||
|
||||
try {
|
||||
return $this->init()->gateway->customer()->find($customer_id);
|
||||
}
|
||||
catch(\Exception $e){
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private function findTokens(string $gateway_customer_reference)
|
||||
{
|
||||
return ClientGatewayToken::where('company_id', $this->company_gateway->company_id)
|
||||
->where('gateway_customer_reference', $gateway_customer_reference)
|
||||
->exists();
|
||||
}
|
||||
|
||||
private function getToken(string $token, string $gateway_customer_reference)
|
||||
{
|
||||
|
||||
return ClientGatewayToken::where('company_id', $this->company_gateway->company_id)
|
||||
->where('gateway_customer_reference', $gateway_customer_reference)
|
||||
->where('token', $token)
|
||||
->first();
|
||||
|
||||
}
|
||||
|
||||
private function findClient(string $email) {
|
||||
return ClientContact::where('company_id', $this->company_gateway->company_id)
|
||||
->where('email', $email)
|
||||
->first()->client ?? false;
|
||||
}
|
||||
|
||||
private function addClientCards(Client $client, array $cards)
|
||||
{
|
||||
|
||||
$this->client = $client;
|
||||
|
||||
foreach($cards as $card) {
|
||||
|
||||
if($this->getToken($card->token, $card->customerId) || Carbon::createFromDate($card->expirationYear, $card->expirationMonth, '1')->lt(now()))
|
||||
continue;
|
||||
|
||||
$payment_meta = new \stdClass();
|
||||
$payment_meta->exp_month = (string) $card->expirationMonth;
|
||||
$payment_meta->exp_year = (string) $card->expirationYear;
|
||||
$payment_meta->brand = (string) $card->cardType;
|
||||
$payment_meta->last4 = (string) $card->last4;
|
||||
$payment_meta->type = GatewayType::CREDIT_CARD;
|
||||
|
||||
$data = [
|
||||
'payment_meta' => $payment_meta,
|
||||
'token' => $card->token,
|
||||
'payment_method_id' => GatewayType::CREDIT_CARD,
|
||||
];
|
||||
|
||||
$this->storeGatewayToken($data, ['gateway_customer_reference' => $card->customerId]);
|
||||
|
||||
nlog("adding card to customer payment profile");
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public function createNinjaClient(mixed $customer): Client
|
||||
{
|
||||
|
||||
$client = ClientFactory::create($this->company_gateway->company_id, $this->company_gateway->user_id);
|
||||
|
||||
$b_business_address = count($customer->addresses) >= 1 ? $customer->addresses[0] : false;
|
||||
$b_shipping_address = count($customer->addresses) > 1 ? $customer->addresses[1] : false;
|
||||
$import_client_data = [];
|
||||
|
||||
if($b_business_address) {
|
||||
|
||||
$braintree_address =
|
||||
[
|
||||
'address1' => $b_business_address->extendedAddress ?? '',
|
||||
'address2' => $b_business_address->streetAddress ?? '',
|
||||
'city' => $b_business_address->locality ?? '',
|
||||
'postal_code' => $b_business_address->postalCode ?? '',
|
||||
'state' => $b_business_address->region ?? '',
|
||||
'country_id' => $b_business_address->countryCodeNumeric ?? '840',
|
||||
];
|
||||
|
||||
$import_client_data = array_merge($import_client_data, $braintree_address);
|
||||
}
|
||||
|
||||
if($b_shipping_address) {
|
||||
|
||||
$braintree_shipping_address =
|
||||
[
|
||||
'shipping_address1' => $b_shipping_address->extendedAddress ?? '',
|
||||
'shipping_address2' => $b_shipping_address->streetAddress ?? '',
|
||||
'shipping_city' => $b_shipping_address->locality ?? '',
|
||||
'shipping_postal_code' => $b_shipping_address->postalCode ?? '',
|
||||
'shipping_state' => $b_shipping_address->region ?? '',
|
||||
'shipping_country_id' => $b_shipping_address->countryCodeNumeric ?? '840',
|
||||
];
|
||||
|
||||
$import_client_data = array_merge($import_client_data, $braintree_shipping_address);
|
||||
|
||||
}
|
||||
|
||||
$client->fill($import_client_data);
|
||||
|
||||
$client->phone = $customer->phone ?? '';
|
||||
$client->name = $customer->company ?? $customer->firstName;
|
||||
|
||||
$settings = $client->settings;
|
||||
$settings->currency_id = (string) $this->company_gateway->company->settings->currency_id;
|
||||
$client->settings = $settings;
|
||||
$client->save();
|
||||
|
||||
$contact = ClientContactFactory::create($this->company_gateway->company_id, $this->company_gateway->user_id);
|
||||
$contact->first_name = $customer->firstName ?? '';
|
||||
$contact->last_name = $customer->lastName ?? '';
|
||||
$contact->email = $customer->email ?? '';
|
||||
$contact->phone = $customer->phone ?? '';
|
||||
$contact->client_id = $client->id;
|
||||
$contact->saveQuietly();
|
||||
|
||||
if (! isset($client->number) || empty($client->number)) {
|
||||
$x = 1;
|
||||
|
||||
do {
|
||||
try {
|
||||
$client->number = $this->getNextClientNumber($client);
|
||||
$client->saveQuietly();
|
||||
|
||||
$this->completed = false;
|
||||
} catch (QueryException $e) {
|
||||
$x++;
|
||||
|
||||
if ($x > 10) {
|
||||
$this->completed = false;
|
||||
}
|
||||
}
|
||||
} while ($this->completed);
|
||||
} else {
|
||||
$client->saveQuietly();
|
||||
}
|
||||
|
||||
return $client;
|
||||
|
||||
}
|
||||
|
||||
public function importCustomers()
|
||||
{
|
||||
$customers = $this->init()->gateway->customer()->all();
|
||||
|
||||
foreach($customers as $c){
|
||||
|
||||
$customer = $this->find($c->id);
|
||||
|
||||
// nlog(count($customer->creditCards). " Exists for {$c->id}");
|
||||
|
||||
if(!$customer)
|
||||
continue;
|
||||
|
||||
$client = $this->findClient($customer->email);
|
||||
|
||||
if(!$this->findTokens($c->id) && !$client) {
|
||||
//customer is not referenced in the system - create client
|
||||
$client = $this->createNinjaClient($customer);
|
||||
// nlog("Creating new Client");
|
||||
}
|
||||
|
||||
$this->addClientCards($client, $customer->creditCards);
|
||||
|
||||
// nlog("Adding Braintree Client: {$c->id} => {$client->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