Merge pull request #8893 from turbo124/v5-develop

Ensure order of Item exports
This commit is contained in:
David Bomba 2023-10-21 07:46:13 +11:00 committed by GitHub
commit 3d3339b942
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 747 additions and 54 deletions

View File

@ -0,0 +1,515 @@
<?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\DataMapper\Settings;
class SettingsData
{
public bool $auto_archive_invoice = false; // @implemented
public string $qr_iban = ''; //@implemented
public string $besr_id = ''; //@implemented
public string $lock_invoices = 'off'; // off, when_sent, when_paid //@implemented
public bool $enable_client_portal_tasks = false; //@ben to implement
public string $show_all_tasks_client_portal = 'invoiced'; // all, uninvoiced, invoiced
public bool $enable_client_portal_password = false; //@implemented
public bool $enable_client_portal = true; //@implemented
public bool $enable_client_portal_dashboard = false; // @TODO There currently is no dashboard, so this is pending
public bool $signature_on_pdf = false; //@implemented
public bool $document_email_attachment = false; //@TODO I assume this is 3rd party attachments on the entity to be included
public string $portal_design_id = '1'; //? @deprecated
public string $timezone_id = ''; //@implemented
public string $date_format_id = ''; //@implemented
public bool $military_time = false; // @TODO Implemented in Tasks only?
public string $language_id = ''; //@implemented
public bool $show_currency_code = false; //@implemented
public string $company_gateway_ids = ''; //@implemented
public string $currency_id = '1'; //@implemented
public string $custom_value1 = ''; //@implemented
public string $custom_value2 = ''; //@implemented
public string $custom_value3 = ''; //@implemented
public string $custom_value4 = ''; //@implemented
public float $default_task_rate = 0; // @TODO Where do we inject this?
public string $payment_terms = ''; //@implemented
public bool $send_reminders = true; //@TODO
public string $custom_message_dashboard = ''; // @TODO There currently is no dashboard, so this is pending
public string $custom_message_unpaid_invoice = '';
public string $custom_message_paid_invoice = '';
public string $custom_message_unapproved_quote = '';
public bool $auto_archive_quote = false; //@implemented
public bool $auto_convert_quote = true; //@implemented
public bool $auto_email_invoice = true; //@only used for Recurring Invoices, if set to false, we never send?
public int $entity_send_time = 6;
public bool $inclusive_taxes = false; //@implemented
public string $quote_footer = ''; //@implemented
public object $translations;
public string $counter_number_applied = 'when_saved'; // when_saved, when_sent //@implemented
public string $quote_number_applied = 'when_saved'; // when_saved, when_sent //@implemented
public string $invoice_number_pattern = ''; //@implemented
public int $invoice_number_counter = 1; //@implemented
public string $recurring_invoice_number_pattern = ''; //@implemented
public int $recurring_invoice_number_counter = 1; //@implemented
public string $quote_number_pattern = ''; //@implemented
public int $quote_number_counter = 1; //@implemented
public string $client_number_pattern = ''; //@implemented
public int $client_number_counter = 1; //@implemented
public string $credit_number_pattern = ''; //@implemented
public int $credit_number_counter = 1; //@implemented
public string $task_number_pattern = ''; //@implemented
public int $task_number_counter = 1; //@implemented
public string $expense_number_pattern = ''; //@implemented
public int $expense_number_counter = 1; //@implemented
public string $recurring_expense_number_pattern = '';
public int $recurring_expense_number_counter = 1;
public string $recurring_quote_number_pattern = '';
public int $recurring_quote_number_counter = 1;
public string $vendor_number_pattern = ''; //@implemented
public int $vendor_number_counter = 1; //@implemented
public string $ticket_number_pattern = ''; //@implemented
public int $ticket_number_counter = 1; //@implemented
public string $payment_number_pattern = ''; //@implemented
public int $payment_number_counter = 1; //@implemented
public string $project_number_pattern = ''; //@implemented
public int $project_number_counter = 1; //@implemented
public string $purchase_order_number_pattern = ''; //@implemented
public int $purchase_order_number_counter = 1; //@implemented
public bool $shared_invoice_quote_counter = false; //@implemented
public bool $shared_invoice_credit_counter = false; //@implemented
public string $recurring_number_prefix = ''; //@implemented
public string $reset_counter_frequency_id = '0'; //@implemented
public string $reset_counter_date = ''; //@implemented
public int $counter_padding = 4; //@implemented
public string $auto_bill = 'off'; // off, always, opt-in, opt-out //@implemented
public string $auto_bill_date = 'on_due_date'; // on_due_date, on_send_date //@implemented
public string $invoice_terms = ''; //@implemented
public string $quote_terms = ''; //@implemented
public int $invoice_taxes = 0; // ? used in AP only?
public string $invoice_design_id = 'Wpmbk5ezJn'; //@implemented
public string $quote_design_id = 'Wpmbk5ezJn'; //@implemented
public string $credit_design_id = 'Wpmbk5ezJn'; //@implemented
public string $purchase_order_design_id = 'Wpmbk5ezJn';
public string $purchase_order_footer = ''; //@implemented
public string $purchase_order_terms = ''; //@implemented
public string $purchase_order_public_notes = ''; //@implemented
public bool $require_purchase_order_signature = false; //@TODO ben to confirm
public string $invoice_footer = ''; //@implemented
public string $credit_footer = ''; //@implemented
public string $credit_terms = ''; //@implemented
public string $invoice_labels = ''; //@TODO used in AP only?
public string $tax_name1 = ''; //@TODO where do we use this?
public float $tax_rate1 = 0; //@TODO where do we use this?
public string $tax_name2 = ''; //@TODO where do we use this?
public float $tax_rate2 = 0; //@TODO where do we use this?
public string $tax_name3 = ''; //@TODO where do we use this?
public float $tax_rate3 = 0; //@TODO where do we use this?
public string $payment_type_id = '0'; //@TODO where do we use this?
public string $valid_until = ''; //@implemented
public bool $show_accept_invoice_terms = false; //@TODO ben to confirm
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 $gmail_sending_user_id = '0'; //@implemented
public string $reply_to_email = ''; //@implemented
public string $reply_to_name = ''; //@implemented
public string $bcc_email = ''; //@TODO
public bool $pdf_email_attachment = false; //@implemented
public bool $ubl_email_attachment = false; //@implemented
public string $email_style = 'light'; // plain, light, dark, custom //@implemented
public string $email_style_custom = ''; // the template itself //@implemented
public string $email_subject_invoice = ''; //@implemented
public string $email_subject_quote = ''; //@implemented
public string $email_subject_credit = ''; //@implemented
public string $email_subject_payment = ''; //@implemented
public string $email_subject_payment_partial = ''; //@implemented
public string $email_subject_statement = ''; //@implemented
public string $email_subject_purchase_order = ''; //@implemented
public string $email_template_purchase_order = ''; //@implemented
public string $email_template_invoice = ''; //@implemented
public string $email_template_credit = ''; //@implemented
public string $email_template_quote = ''; //@implemented
public string $email_template_payment = ''; //@implemented
public string $email_template_payment_partial = ''; //@implemented
public string $email_template_statement = ''; //@implemented
public string $email_subject_reminder1 = ''; //@implemented
public string $email_subject_reminder2 = ''; //@implemented
public string $email_subject_reminder3 = ''; //@implemented
public string $email_subject_reminder_endless = ''; //@implemented
public string $email_template_reminder1 = ''; //@implemented
public string $email_template_reminder2 = ''; //@implemented
public string $email_template_reminder3 = ''; //@implemented
public string $email_template_reminder_endless = ''; //@implemented
public string $email_signature = ''; //@implemented
public bool $enable_email_markup = true; //@TODO -
public string $email_subject_custom1 = ''; //@TODO
public string $email_subject_custom2 = ''; //@TODO
public string $email_subject_custom3 = ''; //@TODO
public string $email_template_custom1 = ''; //@TODO
public string $email_template_custom2 = ''; //@TODO
public string $email_template_custom3 = ''; //@TODO
public bool $enable_reminder1 = false; //@implmemented
public bool $enable_reminder2 = false; //@implmemented
public bool $enable_reminder3 = false; //@implmemented
public bool $enable_reminder_endless = false; //@implmemented
public int $num_days_reminder1 = 0; //@implmemented
public int $num_days_reminder2 = 0; //@implmemented
public int $num_days_reminder3 = 0; //@implmemented
public string $schedule_reminder1 = ''; // (enum: after_invoice_date, before_due_date, after_due_date) implmemented
public string $schedule_reminder2 = ''; // (enum: after_invoice_date, before_due_date, after_due_date) implmemented
public string $schedule_reminder3 = ''; // (enum: after_invoice_date, before_due_date, after_due_date) implmemented
public int $reminder_send_time = 0; // number of seconds from UTC +0 to send reminders @TODO
public float $late_fee_amount1 = 0; //@implemented
public float $late_fee_amount2 = 0; //@implemented
public float $late_fee_amount3 = 0; //@implemented
public float $late_fee_percent1 = 0; //@implemented
public float $late_fee_percent2 = 0; //@implemented
public float $late_fee_percent3 = 0; //@implemented
public string $endless_reminder_frequency_id = '0'; //@implemented
public float $late_fee_endless_amount = 0; //@implemented
public float $late_fee_endless_percent = 0; //@implemented
public bool $client_online_payment_notification = true; //@todo implement in notifications check this bool prior to sending payment notification to client
public bool $client_manual_payment_notification = true; //@todo implement in notifications check this bool prior to sending manual payment notification to client
public string $name = ''; //@implemented
public string $company_logo = ''; //@implemented
public string $website = ''; //@implemented
public string $address1 = ''; //@implemented
public string $address2 = ''; //@implemented
public string $city = ''; //@implemented
public string $state = ''; //@implemented
public string $postal_code = ''; //@implemented
public string $phone = ''; //@implemented
public string $email = ''; //@implemented
public string $country_id; //@implemented
public string $vat_number = ''; //@implemented
public string $id_number = ''; //@implemented
public string $page_size = 'A4'; // Letter, Legal, Tabloid, Ledger, A0, A1, A2, A3, A4, A5, A6
public string $page_layout = 'portrait';
public int $font_size = 16; //@implemented
public string $primary_font = 'Roboto';
public string $secondary_font = 'Roboto';
public string $primary_color = '#298AAB';
public string $secondary_color = '#7081e0';
public bool $page_numbering = false;
public string $page_numbering_alignment = 'C'; // C, R, L
public bool $hide_paid_to_date = false; //@TODO where?
public bool $embed_documents = false; //@TODO where?
public bool $all_pages_header = false; //@deprecated 31-05-2021
public bool $all_pages_footer = false; //@deprecated 31-05-2021
public string $pdf_variables = ''; //@implemented
public string $portal_custom_head = ''; //@TODO @BEN
public string $portal_custom_css = ''; //@TODO @BEN
public string $portal_custom_footer = ''; //@TODO @BEN
public string $portal_custom_js = ''; //@TODO @BEN
public bool $client_can_register = false; //@deprecated 04/06/2021
public string $client_portal_terms = ''; //@TODO @BEN
public string $client_portal_privacy_policy = ''; //@TODO @BEN
public bool $client_portal_enable_uploads = false; //@implemented
public bool $client_portal_allow_under_payment = false; //@implemented
public float $client_portal_under_payment_minimum = 0; //@implemented
public bool $client_portal_allow_over_payment = false; //@implemented
public string $use_credits_payment = 'off'; // always, option, off //@implemented
public bool $hide_empty_columns_on_pdf = false;
public string $email_from_name = '';
public bool $auto_archive_invoice_cancelled = false;
public bool $vendor_portal_enable_uploads = false;
public bool $send_email_on_mark_paid = false;
public string $postmark_secret = '';
public string $custom_sending_email = '';
public string $mailgun_secret = '';
public string $mailgun_domain = '';
public string $mailgun_endpoint = 'api.mailgun.net'; // api.eu.mailgun.net
public bool $auto_bill_standard_invoices = false;
public string $email_alignment = 'center'; // center, left, right
public bool $show_email_footer = true;
public string $company_logo_size = '';
public bool $show_paid_stamp = false;
public bool $show_shipping_address = false;
public bool $accept_client_input_quote_approval = false;
public bool $allow_billable_task_items = true;
public bool $show_task_item_description = false;
public bool $client_initiated_payments = false;
public float $client_initiated_payments_minimum = 0;
public bool $sync_invoice_quote_columns = true;
public string $e_invoice_type = 'EN16931';
public string $default_expense_payment_type_id = '0';
public bool $enable_e_invoice = false;
public string $classification = '';
private mixed $object;
public function cast(mixed $object)
{
if(is_array($object))
$object = (object)$object;
if (is_object($object)) {
foreach ($object as $key => $value) {
try{
settype($object->{$key}, gettype($this->{$key}));
}
catch(\Exception | \Error | \Throwable $e){
if(property_exists($this, $key))
$object->{$key} = $this->{$key};
else
unset($object->{$key});
}
// if(!property_exists($this, $key)) {
// unset($object->{$key});
// }
// elseif(is_array($object->{$key}) && gettype($this->{$key} != 'array')){
// $object->{$key} = $this->{$key};
// }
// else {
// settype($object->{$key}, gettype($this->{$key}));
// }
}
}
$this->object = $object;
return $this;
}
public function toObject(): object
{
return (object)$this->object;
}
public function toArray(): array
{
return (array)$this->object;
}
}

View File

@ -1154,9 +1154,9 @@ class BaseExport
$clean_row[$key]['entity'] = $report_keys[0]; $clean_row[$key]['entity'] = $report_keys[0];
$clean_row[$key]['id'] = $report_keys[1] ?? $report_keys[0]; $clean_row[$key]['id'] = $report_keys[1] ?? $report_keys[0];
$clean_row[$key]['hashed_id'] = $report_keys[0] == $entity ? null : $resource->{$report_keys[0]}->hashed_id ?? null; $clean_row[$key]['hashed_id'] = $report_keys[0] == $entity ? null : $resource->{$report_keys[0]}->hashed_id ?? null;
$clean_row[$key]['value'] = isset($row[$column_key]) ? $row[$column_key] : $row[$report_keys[1]]; $clean_row[$key]['value'] = isset($row[$column_key]) ? $row[$column_key] : $row[$value];
$clean_row[$key]['identifier'] = $value; $clean_row[$key]['identifier'] = $value;
$clean_row[$key]['display_value'] = isset($row[$column_key]) ? $row[$column_key] : $row[$report_keys[1]]; $clean_row[$key]['display_value'] = isset($row[$column_key]) ? $row[$column_key] : $row[$value];
} }

View File

@ -137,16 +137,16 @@ class InvoiceItemExport extends BaseExport
if (str_contains($key, "item.")) { if (str_contains($key, "item.")) {
$key = str_replace("item.", "", $key); $tmp_key = str_replace("item.", "", $key);
if($key == 'type_id') if($tmp_key == 'type_id')
$key = 'type'; $tmp_key = 'type';
if($key == 'tax_id') if($tmp_key == 'tax_id')
$key = 'tax_category'; $tmp_key = 'tax_category';
if (property_exists($item, $key)) { if (property_exists($item, $tmp_key)) {
$item_array[$key] = $item->{$key}; $item_array[$key] = $item->{$tmp_key};
} }
else { else {
$item_array[$key] = ''; $item_array[$key] = '';
@ -156,6 +156,8 @@ class InvoiceItemExport extends BaseExport
$transformed_items = array_merge($transformed_invoice, $item_array); $transformed_items = array_merge($transformed_invoice, $item_array);
$entity = $this->decorateAdvancedFields($invoice, $transformed_items); $entity = $this->decorateAdvancedFields($invoice, $transformed_items);
$entity = array_merge(array_flip(array_values($this->input['report_keys'])), $entity);
$this->storage_array[] = $entity; $this->storage_array[] = $entity;

View File

@ -127,18 +127,18 @@ class PurchaseOrderItemExport extends BaseExport
if (str_contains($key, "item.")) { if (str_contains($key, "item.")) {
$key = str_replace("item.", "", $key); $tmp_key = str_replace("item.", "", $key);
if($key == 'type_id') { if($tmp_key == 'type_id') {
$keyval = 'type'; $tmp_key = 'type';
} }
if($key == 'tax_id') { if($tmp_key == 'tax_id') {
$keyval = 'tax_category'; $tmp_key = 'tax_category';
} }
if (property_exists($item, $key)) { if (property_exists($item, $tmp_key)) {
$item_array[$key] = $item->{$key}; $item_array[$key] = $item->{$tmp_key};
} else { } else {
$item_array[$key] = ''; $item_array[$key] = '';
} }
@ -147,6 +147,7 @@ class PurchaseOrderItemExport extends BaseExport
$transformed_items = array_merge($transformed_purchase_order, $item_array); $transformed_items = array_merge($transformed_purchase_order, $item_array);
$entity = $this->decorateAdvancedFields($purchase_order, $transformed_items); $entity = $this->decorateAdvancedFields($purchase_order, $transformed_items);
$entity = array_merge(array_flip(array_values($this->input['report_keys'])), $entity);
$this->storage_array[] = $entity; $this->storage_array[] = $entity;
} }

View File

@ -133,16 +133,16 @@ class QuoteItemExport extends BaseExport
if (str_contains($key, "item.")) { if (str_contains($key, "item.")) {
$key = str_replace("item.", "", $key); $tmp_key = str_replace("item.", "", $key);
if($key == 'type_id') if($tmp_key == 'type_id')
$key = 'type'; $tmp_key = 'type';
if($key == 'tax_id') if($tmp_key == 'tax_id')
$key = 'tax_category'; $tmp_key = 'tax_category';
if (property_exists($item, $key)) { if (property_exists($item, $tmp_key)) {
$item_array[$key] = $item->{$key}; $item_array[$key] = $item->{$tmp_key};
} }
else { else {
$item_array[$key] = ''; $item_array[$key] = '';
@ -152,6 +152,7 @@ class QuoteItemExport extends BaseExport
$transformed_items = array_merge($transformed_quote, $item_array); $transformed_items = array_merge($transformed_quote, $item_array);
$entity = $this->decorateAdvancedFields($quote, $transformed_items); $entity = $this->decorateAdvancedFields($quote, $transformed_items);
$entity = array_merge(array_flip(array_values($this->input['report_keys'])), $entity);
$this->storage_array[] = $entity; $this->storage_array[] = $entity;
} }

View File

@ -180,8 +180,6 @@ class StoreClientRequest extends Request
public function messages() public function messages()
{ {
return [ return [
// 'unique' => ctrans('validation.unique', ['attribute' => ['email','number']),
//'required' => trans('validation.required', ['attribute' => 'email']),
'contacts.*.email.required' => ctrans('validation.email', ['attribute' => 'email']), 'contacts.*.email.required' => ctrans('validation.email', ['attribute' => 'email']),
'currency_code' => 'Currency code does not exist', 'currency_code' => 'Currency code does not exist',
]; ];

View File

@ -11,11 +11,13 @@
namespace App\Http\Requests\GroupSetting; namespace App\Http\Requests\GroupSetting;
use App\DataMapper\ClientSettings;
use App\Http\Requests\Request;
use App\Http\ValidationRules\ValidClientGroupSettingsRule;
use App\Models\Account; use App\Models\Account;
use App\Models\GroupSetting; use App\Models\GroupSetting;
use App\Http\Requests\Request;
use App\DataMapper\ClientSettings;
use App\DataMapper\CompanySettings;
use App\DataMapper\Settings\SettingsData;
use App\Http\ValidationRules\ValidClientGroupSettingsRule;
class StoreGroupSettingRequest extends Request class StoreGroupSettingRequest extends Request
{ {
@ -26,12 +28,18 @@ class StoreGroupSettingRequest extends Request
*/ */
public function authorize() : bool public function authorize() : bool
{ {
return auth()->user()->can('create', GroupSetting::class) && auth()->user()->account->hasFeature(Account::FEATURE_API); /** @var \App\Models\User $user */
$user = auth()->user();
return $user->can('create', GroupSetting::class) && $user->account->hasFeature(Account::FEATURE_API);
} }
public function rules() public function rules()
{ {
$rules['name'] = 'required|unique:group_settings,name,null,null,company_id,'.auth()->user()->companyId(); /** @var \App\Models\User $user */
$user = auth()->user();
$rules['name'] = 'required|unique:group_settings,name,null,null,company_id,'.$user->companyId();
$rules['settings'] = new ValidClientGroupSettingsRule(); $rules['settings'] = new ValidClientGroupSettingsRule();
@ -42,15 +50,12 @@ class StoreGroupSettingRequest extends Request
{ {
$input = $this->all(); $input = $this->all();
$group_settings = ClientSettings::defaults(); if (array_key_exists('settings', $input)) {
$input['settings'] = $this->filterSaveableSettings($input['settings']);
if (array_key_exists('settings', $input) && ! empty($input['settings'])) { }
foreach ($input['settings'] as $key => $value) { else {
$group_settings->{$key} = $value; $input['settings'] = (array)ClientSettings::defaults();
}
} }
$input['settings'] = (array)$group_settings;
$this->replace($input); $this->replace($input);
} }
@ -61,4 +66,38 @@ class StoreGroupSettingRequest extends Request
'settings' => 'settings must be a valid json structure', 'settings' => 'settings must be a valid json structure',
]; ];
} }
/**
* For the hosted platform, we restrict the feature settings.
*
* This method will trim the company settings object
* down to the free plan setting properties which
* are saveable
*
* @param object $settings
* @return array $settings
*/
private function filterSaveableSettings($settings)
{
/** @var \App\Models\User $user */
$user = auth()->user();
$settings_data = new SettingsData();
$settings = $settings_data->cast($settings)->toObject();
if (! $user->account->isFreeHostedClient()) {
return (array)$settings;
}
$saveable_casts = CompanySettings::$free_plan_casts;
foreach ($settings as $key => $value) {
if (! array_key_exists($key, $saveable_casts)) {
unset($settings->{$key});
}
}
return (array)$settings;
}
} }

View File

@ -11,8 +11,9 @@
namespace App\Http\Requests\GroupSetting; namespace App\Http\Requests\GroupSetting;
use App\DataMapper\CompanySettings;
use App\Http\Requests\Request; use App\Http\Requests\Request;
use App\DataMapper\CompanySettings;
use App\DataMapper\Settings\SettingsData;
use App\Http\ValidationRules\ValidClientGroupSettingsRule; use App\Http\ValidationRules\ValidClientGroupSettingsRule;
class UpdateGroupSettingRequest extends Request class UpdateGroupSettingRequest extends Request
@ -62,10 +63,14 @@ class UpdateGroupSettingRequest extends Request
*/ */
private function filterSaveableSettings($settings) private function filterSaveableSettings($settings)
{ {
$account = $this->group_setting->company->account; /** @var \App\Models\User $user */
$user = auth()->user();
if (! $account->isFreeHostedClient()) { $settings_data = new SettingsData();
return $settings; $settings = $settings_data->cast($settings)->toObject();
if (! $user->account->isFreeHostedClient()) {
return (array)$settings;
} }
$saveable_casts = CompanySettings::$free_plan_casts; $saveable_casts = CompanySettings::$free_plan_casts;
@ -75,7 +80,7 @@ class UpdateGroupSettingRequest extends Request
unset($settings->{$key}); unset($settings->{$key});
} }
} }
return (array)$settings; return (array)$settings;
} }
} }

View File

@ -56,6 +56,23 @@ 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();
}
private function updateSystemLog(SystemLog $system_log, array $data): void
{
$system_log->log = $data;
$system_log->save();
}
/** /**
* Execute the job. * Execute the job.
* *
@ -135,6 +152,13 @@ class ProcessPostmarkWebhook implements ShouldQueue
$data = array_merge($this->request, ['history' => $this->fetchMessage()]); $data = array_merge($this->request, ['history' => $this->fetchMessage()]);
$sl = $this->getSystemLog($this->request['MessageID']);
if($sl){
$this->updateSystemLog($sl, $data);
return;
}
(new SystemLogger( (new SystemLogger(
$data, $data,
SystemLog::CATEGORY_MAIL, SystemLog::CATEGORY_MAIL,
@ -166,6 +190,13 @@ class ProcessPostmarkWebhook implements ShouldQueue
$data = array_merge($this->request, ['history' => $this->fetchMessage()]); $data = array_merge($this->request, ['history' => $this->fetchMessage()]);
$sl = $this->getSystemLog($this->request['MessageID']);
if($sl) {
$this->updateSystemLog($sl, $data);
return;
}
(new SystemLogger( (new SystemLogger(
$data, $data,
SystemLog::CATEGORY_MAIL, SystemLog::CATEGORY_MAIL,
@ -217,6 +248,13 @@ class ProcessPostmarkWebhook implements ShouldQueue
$data = array_merge($this->request, ['history' => $this->fetchMessage()]); $data = array_merge($this->request, ['history' => $this->fetchMessage()]);
$sl = $this->getSystemLog($this->request['MessageID']);
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(); (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')) // if(config('ninja.notification.slack'))
@ -263,6 +301,13 @@ class ProcessPostmarkWebhook implements ShouldQueue
$data = array_merge($this->request, ['history' => $this->fetchMessage()]); $data = array_merge($this->request, ['history' => $this->fetchMessage()]);
$sl = $this->getSystemLog($this->request['MessageID']);
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(); (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')) { if (config('ninja.notification.slack')) {

View File

@ -109,7 +109,11 @@ class DeletePayment
if ($paymentable_invoice->balance == $paymentable_invoice->amount) { if ($paymentable_invoice->balance == $paymentable_invoice->amount) {
$paymentable_invoice->service()->setStatus(Invoice::STATUS_SENT)->save(); $paymentable_invoice->service()->setStatus(Invoice::STATUS_SENT)->save();
} else { }
elseif($paymentable_invoice->balance == 0){
$paymentable_invoice->service()->setStatus(Invoice::STATUS_PAID)->save();
}
else {
$paymentable_invoice->service()->setStatus(Invoice::STATUS_PARTIAL)->save(); $paymentable_invoice->service()->setStatus(Invoice::STATUS_PARTIAL)->save();
} }
} else { } else {

View File

@ -670,16 +670,16 @@ class HtmlEngine
$data['$payment.transaction_reference'] = ['value' => '', 'label' => ctrans('texts.transaction_reference')]; $data['$payment.transaction_reference'] = ['value' => '', 'label' => ctrans('texts.transaction_reference')];
if ($this->entity_string == 'invoice' && $this->entity->payments()->exists()) { if ($this->entity_string == 'invoice' && $this->entity->net_payments()->exists()) {
$payment_list = '<br><br>'; $payment_list = '<br><br>';
foreach ($this->entity->payments as $payment) { foreach ($this->entity->net_payments as $payment) {
$payment_list .= ctrans('texts.payment_subject') . ": " . $this->formatDate($payment->date, $this->client->date_format()) . " :: " . Number::formatMoney($payment->amount, $this->client) ." :: ". GatewayType::getAlias($payment->gateway_type_id) . "<br>"; $payment_list .= ctrans('texts.payment_subject') . ": " . $this->formatDate($payment->date, $this->client->date_format()) . " :: " . Number::formatMoney($payment->amount, $this->client) ." :: ". GatewayType::getAlias($payment->gateway_type_id) . "<br>";
} }
$data['$payments'] = ['value' => $payment_list, 'label' => ctrans('texts.payments')]; $data['$payments'] = ['value' => $payment_list, 'label' => ctrans('texts.payments')];
$payment = $this->entity->payments()->first(); $payment = $this->entity->net_payments()->first();
$data['$payment.custom1'] = ['value' => $payment->custom_value1, 'label' => $this->helpers->makeCustomField($this->company->custom_fields, 'payment1')]; $data['$payment.custom1'] = ['value' => $payment->custom_value1, 'label' => $this->helpers->makeCustomField($this->company->custom_fields, 'payment1')];
$data['$payment.custom2'] = ['value' => $payment->custom_value2, 'label' => $this->helpers->makeCustomField($this->company->custom_fields, 'payment2')]; $data['$payment.custom2'] = ['value' => $payment->custom_value2, 'label' => $this->helpers->makeCustomField($this->company->custom_fields, 'payment2')];

View File

@ -1171,7 +1171,7 @@ class ReportCsvGenerationTest extends TestCase
public function testQuoteItemsCustomColumnsCsvGeneration() public function testQuoteItemsCustomColumnsCsvGeneration()
{ {
\App\Models\Quote::factory()->create([ $q = \App\Models\Quote::factory()->create([
'user_id' => $this->user->id, 'user_id' => $this->user->id,
'company_id' => $this->company->id, 'company_id' => $this->company->id,
'client_id' => $this->client->id, 'client_id' => $this->client->id,
@ -1217,7 +1217,6 @@ class ReportCsvGenerationTest extends TestCase
$csv = $response->streamedContent(); $csv = $response->streamedContent();
$this->assertEquals('bob', $this->getFirstValueByColumn($csv, 'Client Name')); $this->assertEquals('bob', $this->getFirstValueByColumn($csv, 'Client Name'));
$this->assertEquals('1234', $this->getFirstValueByColumn($csv, 'Quote Number')); $this->assertEquals('1234', $this->getFirstValueByColumn($csv, 'Quote Number'));
$this->assertEquals('10', $this->getFirstValueByColumn($csv, 'Item Quantity')); $this->assertEquals('10', $this->getFirstValueByColumn($csv, 'Item Quantity'));

View File

@ -11,20 +11,21 @@
namespace Tests\Feature; namespace Tests\Feature;
use Tests\TestCase;
use Tests\MockAccountData;
use App\Utils\Traits\MakesHash; use App\Utils\Traits\MakesHash;
use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Model;
use Illuminate\Foundation\Testing\DatabaseTransactions;
use Illuminate\Support\Facades\Session; use Illuminate\Support\Facades\Session;
use Tests\MockAccountData; use App\DataMapper\Settings\SettingsData;
use Tests\TestCase; use Spatie\LaravelData\Support\Wrapping\WrapExecutionType;
class GroupSettingTest extends TestCase class GroupSettingTest extends TestCase
{ {
use MakesHash; use MakesHash;
//use DatabaseTransactions;
use MockAccountData; use MockAccountData;
public $faker;
protected function setUp(): void protected function setUp(): void
{ {
parent::setUp(); parent::setUp();
@ -38,6 +39,85 @@ class GroupSettingTest extends TestCase
$this->makeTestData(); $this->makeTestData();
} }
public function testCastingMagic()
{
$settings = new \stdClass;
$settings->currency_id = '1';
$settings->tax_name1 = '';
$settings->tax_rate1 = 0;
$s = new SettingsData();
$settings = $s->cast($settings)->toObject();
$this->assertEquals("", $settings->tax_name1);
$settings = null;
$settings = new \stdClass;
$settings->currency_id = '1';
$settings->tax_name1 = "1";
$settings->tax_rate1 = 0;
$settings = $s->cast($settings)->toObject();
$this->assertEquals("1", $settings->tax_name1);
$settings = $s->cast($settings)->toArray();
$this->assertEquals("1", $settings['tax_name1']);
$settings = new \stdClass;
$settings->currency_id = '1';
$settings->tax_name1 = [];
$settings->tax_rate1 = 0;
$settings = $s->cast($settings)->toObject();
$this->assertEquals("", $settings->tax_name1);
$settings = $s->cast($settings)->toArray();
$this->assertEquals("", $settings['tax_name1']);
$settings = new \stdClass;
$settings->currency_id = '1';
$settings->tax_name1 = new \stdClass;
$settings->tax_rate1 = 0;
$settings = $s->cast($settings)->toObject();
$this->assertEquals("", $settings->tax_name1);
$settings = $s->cast($settings)->toArray();
$this->assertEquals("", $settings['tax_name1']);
// nlog(json_encode($settings));
}
public function testTaxNameInGroupFilters()
{
$settings = new \stdClass;
$settings->currency_id = '1';
$settings->tax_name1 = '';
$settings->tax_rate1 = 0;
$data = [
'name' => 'testX',
'settings' => $settings,
];
$response = $this->withHeaders([
'X-API-SECRET' => config('ninja.api_secret'),
'X-API-TOKEN' => $this->token,
])->postJson('/api/v1/group_settings', $data);
$response->assertStatus(200);
$arr = $response->json();
$this->assertEquals("", (string)NULL);
$this->assertNotNull($arr['data']['settings']['tax_name1']);
}
public function testAddGroupFilters() public function testAddGroupFilters()
{ {

View File

@ -28,6 +28,10 @@ class GroupSettingsTest extends TestCase
use DatabaseTransactions; use DatabaseTransactions;
use ClientGroupSettingsSaver; use ClientGroupSettingsSaver;
public $company_settings;
public $client_settings;
public $settings;
protected function setUp() :void protected function setUp() :void
{ {
parent::setUp(); parent::setUp();