Merge pull request #7755 from turbo124/v5-stable

v5.5.11
This commit is contained in:
David Bomba 2022-08-17 17:29:14 +10:00 committed by GitHub
commit 9fff6aca8e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
30 changed files with 96965 additions and 96679 deletions

View File

@ -1 +1 @@
5.5.10
5.5.11

View File

@ -166,7 +166,7 @@ class SendRemindersCron extends Command
$invoice_item = new InvoiceItem;
$invoice_item->type_id = '5';
$invoice_item->product_key = trans('texts.fee');
$invoice_item->product_key = ctrans('texts.fee');
$invoice_item->notes = ctrans('texts.late_fee_added', ['date' => $this->translateDate(now()->startOfDay(), $invoice->client->date_format(), $invoice->client->locale())]);
$invoice_item->quantity = 1;
$invoice_item->cost = $fee;

View File

@ -65,6 +65,7 @@ class BaseTransformer
public function getClient($client_name, $client_email)
{
if (! empty($client_name)) {
$client_id_search = $this->company
->clients()

View File

@ -38,13 +38,15 @@ class ClientTransformer extends BaseTransformer
$settings->payment_terms = $data['Payment Terms'];
}
$client_id_proxy = array_key_exists('Customer ID', $data) ? 'Customer ID' : 'Primary Contact ID';
return [
'company_id' => $this->company->id,
'name' => $this->getString($data, 'Company Name'),
'name' => $this->getString($data, 'Display Name'),
'phone' => $this->getString($data, 'Phone'),
'private_notes' => $this->getString($data, 'Notes'),
'website' => $this->getString($data, 'Website'),
'id_number' => $this->getString($data, 'Customer ID'),
'id_number' => $this->getString($data, $client_id_proxy),
'address1' => $this->getString($data, 'Billing Address'),
'address2' => $this->getString($data, 'Billing Street2'),
'city' => $this->getString($data, 'Billing City'),

View File

@ -40,7 +40,7 @@ class InvoiceTransformer extends BaseTransformer
$transformed = [
'company_id' => $this->company->id,
'client_id' => $this->getClient($this->getString($invoice_data, 'Customer ID'), null),
'client_id' => $this->getClient($this->getString($invoice_data, 'Customer ID'), $this->getString($invoice_data, 'Primary Contact EmailID')),
'number' => $this->getString($invoice_data, 'Invoice Number'),
'date' => isset($invoice_data['Invoice Date']) ? date('Y-m-d', strtotime($invoice_data['Invoice Date'])) : null,
'due_date' => isset($invoice_data['Due Date']) ? date('Y-m-d', strtotime($invoice_data['Due Date'])) : null,
@ -51,14 +51,19 @@ class InvoiceTransformer extends BaseTransformer
'balance' => $this->getFloat($invoice_data, 'Balance'),
'status_id' => $invoiceStatusMap[$status =
strtolower($this->getString($invoice_data, 'Invoice Status'))] ?? Invoice::STATUS_SENT,
'terms' => $this->getString($invoice_data, 'Terms & Conditions'),
// 'viewed' => $status === 'viewed',
];
$line_items = [];
foreach ($line_items_data as $record) {
$item_notes_key = array_key_exists('Item Description', $record) ? 'Item Description' : 'Item Desc';
$line_items[] = [
'product_key' => $this->getString($record, 'Item Name'),
'notes' => $this->getString($record, 'Item Description'),
'notes' => $this->getString($record, $item_notes_key),
'cost' => round($this->getFloat($record, 'Item Price'), 2),
'quantity' => $this->getFloat($record, 'Quantity'),
'discount' => $this->getString($record, 'Discount Amount'),

View File

@ -152,6 +152,12 @@ class BaseTransformer
return Number::parseFloat($number);
}
public function getFloatWithSamePrecision($data, $field)
{
$precision = (int) strpos(strrev($data[$field]), ".");
return round($data[$field], $precision);
}
/**
* @param $name
*

View File

@ -39,11 +39,11 @@ class InvoiceTransformer extends BaseTransformer
'is_sent' => $this->getString($data, 'invoice.is_sent'),
'private_notes' => $this->getString($data, 'invoice.private_notes'),
'tax_name1' => $this->getString($data, 'invoice.tax_name1'),
'tax_rate1' => $this->getFloat($data, 'invoice.tax_rate1'),
'tax_rate1' => $this->getFloatWithSamePrecision($data, 'invoice.tax_rate1'),
'tax_name2' => $this->getString($data, 'invoice.tax_name2'),
'tax_rate2' => $this->getFloat($data, 'invoice.tax_rate2'),
'tax_rate2' => $this->getFloatWithSamePrecision($data, 'invoice.tax_rate2'),
'tax_name3' => $this->getString($data, 'invoice.tax_name3'),
'tax_rate3' => $this->getFloat($data, 'invoice.tax_rate3'),
'tax_rate3' => $this->getFloatWithSamePrecision($data, 'invoice.tax_rate3'),
'custom_value1' => $this->getString($data, 'invoice.custom_value1'),
'custom_value2' => $this->getString($data, 'invoice.custom_value2'),
'custom_value3' => $this->getString($data, 'invoice.custom_value3'),

View File

@ -102,6 +102,17 @@ class NinjaMailerJob implements ShouldQueue
$this->nmo->mailable->tag($this->company->company_key);
if($this->nmo->invitation)
{
$this->nmo
->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());

View File

@ -26,6 +26,7 @@ use App\Models\Company;
use App\Models\CreditInvitation;
use App\Models\InvoiceInvitation;
use App\Models\Payment;
use App\Models\PurchaseOrderInvitation;
use App\Models\QuoteInvitation;
use App\Models\RecurringInvoiceInvitation;
use App\Models\SystemLog;
@ -283,6 +284,8 @@ class ProcessPostmarkWebhook implements ShouldQueue
return $invitation;
elseif($invitation = CreditInvitation::where('message_id', $message_id)->first())
return $invitation;
elseif($invitation = PurchaseOrderInvitation::where('message_id', $message_id)->first())
return $invitation;
else
return $invitation;
}

View File

@ -12,9 +12,15 @@
namespace App\Listeners\Mail;
use App\Libraries\MultiDB;
use App\Models\CreditInvitation;
use App\Models\InvoiceInvitation;
use App\Models\PurchaseOrderInvitation;
use App\Models\QuoteInvitation;
use App\Models\RecurringInvoiceInvitation;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Mail\Events\MessageSent;
use Illuminate\Support\Facades\Notification;
use Symfony\Component\Mime\MessageConverter;
class MailSentListener implements ShouldQueue
{
@ -35,19 +41,50 @@ class MailSentListener implements ShouldQueue
*/
public function handle(MessageSent $event)
{
nlog("mail listener");
nlog($event);
// if (property_exists($event->message, 'invitation') && $event->message->invitation) {
// MultiDB::setDb($event->sent->invitation->company->db);
// if ($event->message->getHeaders()->get('x-pm-message-id')) {
// $postmark_id = $event->sent->getHeaders()->get('x-pm-message-id')->getValue();
$message_id = $event->sent->getMessageId();
$message = MessageConverter::toEmail($event->sent->getOriginalMessage());
$invitation_key = $message->getHeaders()->get('x-invitation')->getValue();
if($message_id && $invitation_key)
{
$invitation = $this->discoverInvitation($invitation_key);
if(!$invitation)
return;
$invitation->message_id = $message_id;
$invitation->save();
}
// // nlog($postmark_id);
// $invitation = $event->sent->invitation;
// $invitation->message_id = $postmark_id;
// $invitation->save();
// }
// }
}
private function discoverInvitation($key)
{
$invitation = false;
foreach (MultiDB::$dbs as $db)
{
if($invitation = InvoiceInvitation::on($db)->where('key', $key)->first())
return $invitation;
elseif($invitation = QuoteInvitation::on($db)->where('key', $key)->first())
return $invitation;
elseif($invitation = RecurringInvoiceInvitation::on($db)->where('key', $key)->first())
return $invitation;
elseif($invitation = CreditInvitation::on($db)->where('key', $key)->first())
return $invitation;
elseif($invitation = PurchaseOrderInvitation::on($db)->where('key', $key)->first())
return $invitation;
}
return $invitation;
}
}

View File

@ -271,9 +271,9 @@ class EventServiceProvider extends ServiceProvider
],
MessageSending::class => [
],
// MessageSent::class => [
// MailSentListener::class,
// ],
MessageSent::class => [
MailSentListener::class,
],
UserWasCreated::class => [
CreatedUserActivity::class,
SendVerificationNotification::class,

View File

@ -50,10 +50,8 @@ class Design extends BaseDesign
/** Construct options */
public $options;
/** @var Invoice[] */
public $invoices;
/** @var Payment[] */
public $payments;
public $settings_object;

View File

@ -80,7 +80,6 @@ class ConvertQuote
/**
* Only create the invitations that are defined on the quote.
*
* @return Invoice $invoice
*/
private function createConversionInvitations($invoice, $quote)
{

View File

@ -129,7 +129,8 @@ class QuoteService
/**
* Sometimes we need to refresh the
* PDF when it is updated etc.
* @return InvoiceService
*
* @return QuoteService
*/
public function touchPdf($force = false)
{

View File

@ -840,7 +840,6 @@ class SubscriptionService
* Get the single charge products for the
* subscription
*
* @return ?Product Collection
*/
public function products()
{
@ -859,7 +858,6 @@ class SubscriptionService
* Get the recurring products for the
* subscription
*
* @return ?Product Collection
*/
public function recurring_products()
{

View File

@ -42,8 +42,8 @@ class CompanyUserTransformer extends EntityTransformer
return [
'permissions' => $company_user->permissions ?: '',
'notifications' => (object) $company_user->notifications ?: $blank_obj,
'settings' => (object) $company_user->settings ?: $blank_obj,
'notifications' => $company_user->notifications ? (object) $company_user->notifications : $blank_obj,
'settings' => $company_user->settings ? (object) $company_user->settings : $blank_obj,
'is_owner' => (bool) $company_user->is_owner,
'is_admin' => (bool) $company_user->is_admin,
'is_locked' => (bool) $company_user->is_locked,

View File

@ -80,7 +80,6 @@ class CreditTransformer extends EntityTransformer
'amount' => (float) $credit->amount,
'balance' => (float) $credit->balance,
'client_id' => (string) $this->encodePrimaryKey($credit->client_id),
'vendor_id' => (string) $this->encodePrimaryKey($credit->vendor_id),
'status_id' => (string) ($credit->status_id ?: 1),
'design_id' => (string) $this->encodePrimaryKey($credit->design_id),
'created_at' => (int) $credit->created_at,

View File

@ -137,7 +137,6 @@ class RecurringInvoiceTransformer extends EntityTransformer
'due_date_days' => (string) $invoice->due_date_days ?: '',
'paid_to_date' => (float) $invoice->paid_to_date,
'subscription_id' => (string) $this->encodePrimaryKey($invoice->subscription_id),
'recurring_dates' => (array) [],
];
if (request()->has('show_dates') && request()->query('show_dates') == 'true') {

View File

@ -14,8 +14,8 @@ return [
'require_https' => env('REQUIRE_HTTPS', true),
'app_url' => rtrim(env('APP_URL', ''), '/'),
'app_domain' => env('APP_DOMAIN', 'invoicing.co'),
'app_version' => '5.5.10',
'app_tag' => '5.5.10',
'app_version' => '5.5.11',
'app_tag' => '5.5.11',
'minimum_client_version' => '5.0.16',
'terms_version' => '1.0.1',
'api_secret' => env('API_SECRET', ''),

View File

@ -4730,6 +4730,43 @@ $LANG = array(
'converted_to_expenses' => 'Successfully converted to expenses',
'entity_removed' => 'This document has been removed, please contact the vendor for further information',
'entity_removed_title' => 'Document no longer available',
'field' => 'Field',
'period' => 'Period',
'fields_per_row' => 'Fields Per Row',
'total_active_invoices' => 'Active Invoices',
'total_outstanding_invoices' => 'Outstanding Invoices',
'total_completed_payments' => 'Completed Payments',
'total_refunded_payments' => 'Refunded Payments',
'total_active_quotes' => 'Active Quotes',
'total_approved_quotes' => 'Approved Quotes',
'total_unapproved_quotes' => 'Unapproved Quotes',
'total_logged_tasks' => 'Logged Tasks',
'total_invoiced_tasks' => 'Invoiced Tasks',
'total_paid_tasks' => 'Paid Tasks',
'total_logged_expenses' => 'Logged Expenses',
'total_pending_expenses' => 'Pending Expenses',
'total_invoiced_expenses' => 'Invoiced Expenses',
'total_invoice_paid_expenses' => 'Invoice Paid Expenses',
'vendor_portal' => 'Vendor Portal',
'send_code' => 'Send Code',
'save_to_upload_documents' => 'Save the record to upload documents',
'expense_tax_rates' => 'Expense Tax Rates',
'invoice_item_tax_rates' => 'Invoice Item Tax Rates',
'verified_phone_number' => 'Successfully verified phone number',
'code_was_sent' => 'A code has been sent via SMS',
'resend' => 'Resend',
'verify' => 'Verify',
'enter_phone_number' => 'Please provide a phone number',
'invalid_phone_number' => 'Invalid phone number',
'verify_phone_number' => 'Verify Phone Number',
'verify_phone_number_help' => 'Please verify your phone number to send emails',
'merged_clients' => 'Successfully merged clients',
'merge_into' => 'Merge Into',
'php81_required' => 'Note: v5.5 requires PHP 8.1',
'bulk_email_purchase_orders' => 'Email Purchase Orders',
'bulk_email_invoices' => 'Email Invoices',
'bulk_email_quotes' => 'Email Quotes',
'bulk_email_credits' => 'Email Credits',
);
return $LANG;

View File

@ -200,7 +200,7 @@ $LANG = array(
'removed_logo' => 'Logotipo removido com sucesso',
'sent_message' => 'Mensagem enviada com sucesso',
'invoice_error' => 'Assegure-se de selecionar um cliente e corrigir quaisquer erros',
'limit_clients' => 'Desculpe, isto irá exceder o limite de :count clientes',
'limit_clients' => 'Sorry, this will exceed the limit of :count clients. Please upgrade to a paid plan.',
'payment_error' => 'Ocorreu um erro ao processar seu pagamento. Por favor tente novamente mais tarde.',
'registration_required' => 'Favor cadastre-se para enviar uma fatura por email',
'confirmation_required' => 'Por favor confirme seu endereço de email, :link para re-enviar o email de confirmação.',
@ -2241,7 +2241,7 @@ Quando tiver as quantias, volte a esta página de formas de pagamento e clique "
'navigation_variables' => 'Variáveis de Navegação',
'custom_variables' => 'Variáveis Personalizadas',
'invalid_file' => 'Tipo de arquivo inválido',
'add_documents_to_invoice' => 'Adicionar documentos à fatura',
'add_documents_to_invoice' => 'Add Documents to Invoice',
'mark_expense_paid' => 'Marcar como pago',
'white_label_license_error' => 'Falha ao validar a licença, verifique storage/logs/laravel-error.log para mais detalhes.',
'plan_price' => 'Preço do Plano',
@ -4628,6 +4628,102 @@ Quando tiver as quantias, volte a esta página de formas de pagamento e clique "
'notification_purchase_order_accepted_subject' => 'Purchase Order :purchase_order was accepted by :vendor',
'notification_purchase_order_accepted' => 'The following vendor :vendor accepted Purchase Order :purchase_order for :amount.',
'amount_received' => 'Amount received',
'purchase_order_already_expensed' => 'Already converted to an expense.',
'convert_to_expense' => 'Convert to Expense',
'add_to_inventory' => 'Add to Inventory',
'added_purchase_order_to_inventory' => 'Successfully added purchase order to inventory',
'added_purchase_orders_to_inventory' => 'Successfully added purchase orders to inventory',
'client_document_upload' => 'Client Document Upload',
'vendor_document_upload' => 'Vendor Document Upload',
'vendor_document_upload_help' => 'Enable vendors to upload documents',
'are_you_enjoying_the_app' => 'Are you enjoying the app?',
'yes_its_great' => 'Yes, it"s great!',
'not_so_much' => 'Not so much',
'would_you_rate_it' => 'Great to hear! Would you like to rate it?',
'would_you_tell_us_more' => 'Sorry to hear it! Would you like to tell us more?',
'sure_happy_to' => 'Sure, happy to',
'no_not_now' => 'No, not now',
'add' => 'Add',
'last_sent_template' => 'Last Sent Template',
'enable_flexible_search' => 'Enable Flexible Search',
'enable_flexible_search_help' => 'Match non-contiguous characters, ie. "ct" matches "cat"',
'vendor_details' => 'Vendor Details',
'purchase_order_details' => 'Purchase Order Details',
'qr_iban' => 'QR IBAN',
'besr_id' => 'BESR ID',
'clone_to_purchase_order' => 'Clone to PO',
'vendor_email_not_set' => 'Vendor does not have an email address set',
'bulk_send_email' => 'Send Email',
'marked_purchase_order_as_sent' => 'Successfully marked purchase order as sent',
'marked_purchase_orders_as_sent' => 'Successfully marked purchase orders as sent',
'accepted_purchase_order' => 'Successfully accepted purchase order',
'accepted_purchase_orders' => 'Successfully accepted purchase orders',
'cancelled_purchase_order' => 'Successfully cancelled purchase order',
'cancelled_purchase_orders' => 'Successfully cancelled purchase orders',
'please_select_a_vendor' => 'Please select a vendor',
'purchase_order_total' => 'Purchase Order Total',
'email_purchase_order' => 'Email Purchase Order',
'bulk_email_purchase_order' => 'Email Purchase Order',
'disconnected_email' => 'Successfully disconnected email',
'connect_email' => 'Connect Email',
'disconnect_email' => 'Disconnect Email',
'use_web_app_to_connect_microsoft' => 'Please use the web app to connect to Microsoft',
'email_provider' => 'Email Provider',
'connect_microsoft' => 'Connect Microsoft',
'disconnect_microsoft' => 'Disconnect Microsoft',
'connected_microsoft' => 'Successfully connected Microsoft',
'disconnected_microsoft' => 'Successfully disconnected Microsoft',
'microsoft_sign_in' => 'Login with Microsoft',
'microsoft_sign_up' => 'Sign up with Microsoft',
'emailed_purchase_order' => 'Successfully queued purchase order to be sent',
'emailed_purchase_orders' => 'Successfully queued purchase orders to be sent',
'enable_react_app' => 'Change to the React web app',
'purchase_order_design' => 'Purchase Order Design',
'purchase_order_terms' => 'Purchase Order Terms',
'purchase_order_footer' => 'Purchase Order Footer',
'require_purchase_order_signature' => 'Purchase Order Signature',
'require_purchase_order_signature_help' => 'Require vendor to provide their signature.',
'new_purchase_order' => 'New Purchase Order',
'edit_purchase_order' => 'Edit Purchase Order',
'created_purchase_order' => 'Successfully created purchase order',
'updated_purchase_order' => 'Successfully updated purchase order',
'archived_purchase_order' => 'Successfully archived purchase order',
'deleted_purchase_order' => 'Successfully deleted purchase order',
'removed_purchase_order' => 'Successfully removed purchase order',
'restored_purchase_order' => 'Successfully restored purchase order',
'search_purchase_order' => 'Search Purchase Order',
'search_purchase_orders' => 'Search Purchase Orders',
'login_url' => 'Login URL',
'enable_applying_payments' => 'Enable Applying Payments',
'enable_applying_payments_help' => 'Support separately creating and applying payments',
'stock_quantity' => 'Stock Quantity',
'notification_threshold' => 'Notification Threshold',
'track_inventory' => 'Track Inventory',
'track_inventory_help' => 'Display a product stock field and update when invoices are sent',
'stock_notifications' => 'Stock Notifications',
'stock_notifications_help' => 'Send an email when the stock reaches the threshold',
'vat' => 'VAT',
'view_map' => 'View Map',
'set_default_design' => 'Set Default Design',
'add_gateway_help_message' => 'Add a payment gateway (ie. Stripe, WePay or PayPal) to accept online payments',
'purchase_order_issued_to' => 'Purchase Order issued to',
'archive_task_status' => 'Archive Task Status',
'delete_task_status' => 'Delete Task Status',
'restore_task_status' => 'Restore Task Status',
'lang_Hebrew' => 'Hebrew',
'price_change_accepted' => 'Price change accepted',
'price_change_failed' => 'Price change failed with code',
'restore_purchases' => 'Restore Purchases',
'activate' => 'Activate',
'connect_apple' => 'Connect Apple',
'disconnect_apple' => 'Disconnect Apple',
'disconnected_apple' => 'Successfully disconnected Apple',
'send_now' => 'Send Now',
'received' => 'Received',
'converted_to_expense' => 'Successfully converted to expense',
'converted_to_expenses' => 'Successfully converted to expenses',
'entity_removed' => 'This document has been removed, please contact the vendor for further information',
'entity_removed_title' => 'Document no longer available',
);
return $LANG;

File diff suppressed because it is too large Load Diff

View File

@ -57,6 +57,16 @@
<directory name="app" />
</errorLevel>
</UndefinedMagicPropertyFetch>
<TooManyArguments>
<errorLevel type="suppress">
<directory name="app" />
</errorLevel>
</TooManyArguments>
<RedundantCast>
<errorLevel type="suppress">
<directory name="app" />
</errorLevel>
</RedundantCast>
<InvalidNullableReturnType>
<errorLevel type="suppress">
<directory name="app" />

View File

@ -7,7 +7,7 @@ const RESOURCES = {
"canvaskit/profiling/canvaskit.js": "ae2949af4efc61d28a4a80fffa1db900",
"canvaskit/profiling/canvaskit.wasm": "95e736ab31147d1b2c7b25f11d4c32cd",
"canvaskit/canvaskit.wasm": "4b83d89d9fecbea8ca46f2f760c5a9ba",
"main.dart.js": "1cc79379f20b668b6dd079708cb8101a",
"main.dart.js": "809c193905ea4c80a7c0b2b0e484e1db",
"favicon.ico": "51636d3a390451561744c42188ccd628",
"assets/AssetManifest.json": "759f9ef9973f7e26c2a51450b55bb9fa",
"assets/assets/google_fonts/Roboto-Regular.ttf": "8a36205bd9b83e03af0591a004bc97f4",
@ -295,7 +295,7 @@ const RESOURCES = {
"assets/FontManifest.json": "087fb858dc3cbfbf6baf6a30004922f1",
"assets/NOTICES": "254a5bf1eeb00601955e148b31cb925c",
"flutter.js": "eb2682e33f25cd8f1fc59011497c35f8",
"/": "2e60c2029275df3d540922455395f83c",
"/": "f1ab1648b6acf56aebbd6ae07968a461",
"favicon.png": "dca91c54388f52eded692718d5a98b8b",
"version.json": "a10748384e57f928f4d2871ac7563faf",
"manifest.json": "ef43d90e57aa7682d7e2cfba2f484a40",

84847
public/main.dart.js vendored

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

89465
public/main.foss.dart.js vendored

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -21,6 +21,53 @@ use Tests\TestCase;
*/
class NumberTest extends TestCase
{
public function testFloatPrecision()
{
$value = 1.1;
$precision = (int) strpos(strrev($value), ".");
$result = round($value, $precision);
$this->assertEquals(1.1, $result);
}
public function testFloatPrecision1()
{
$value = "1.1";
$precision = (int) strpos(strrev($value), ".");
$result = round($value, $precision);
$this->assertEquals(1.1, $result);
}
public function testFloatPrecision2()
{
$value = 9.975;
$precision = (int) strpos(strrev($value), ".");
$result = round($value, $precision);
$this->assertEquals(9.975, $result);
}
public function testFloatPrecision3()
{
$value = "9.975";
$precision = (int) strpos(strrev($value), ".");
$result = round($value, $precision);
$this->assertEquals(9.975, $result);
}
public function testRoundingThreeLow()
{
$rounded = Number::roundValue(3.144444444444, 3);