From 25d3c8d20972f58281cb70451fc524c71b352de6 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Mon, 24 Apr 2023 20:35:26 +1000 Subject: [PATCH 1/9] Improvements for eager loading --- app/Http/Controllers/CreditController.php | 2 +- app/Http/Middleware/TokenAuth.php | 7 ++++--- app/Models/RecurringInvoice.php | 4 ++++ app/Transformers/RecurringInvoiceTransformer.php | 1 - 4 files changed, 9 insertions(+), 5 deletions(-) diff --git a/app/Http/Controllers/CreditController.php b/app/Http/Controllers/CreditController.php index 7efebce877b2..336706ea3668 100644 --- a/app/Http/Controllers/CreditController.php +++ b/app/Http/Controllers/CreditController.php @@ -545,7 +545,7 @@ class CreditController extends BaseController } }); - return $this->listResponse(Credit::withTrashed()->company()->whereIn('id', $request->ids)); + return $this->listResponse(Credit::with(['invitations','documents'])->withTrashed()->company()->whereIn('id', $request->ids)); } public function action(ActionCreditRequest $request, Credit $credit, $action) diff --git a/app/Http/Middleware/TokenAuth.php b/app/Http/Middleware/TokenAuth.php index 00858a707b0a..e73ccb00fcab 100644 --- a/app/Http/Middleware/TokenAuth.php +++ b/app/Http/Middleware/TokenAuth.php @@ -30,7 +30,10 @@ class TokenAuth */ public function handle($request, Closure $next) { - if ($request->header('X-API-TOKEN') && ($company_token = CompanyToken::with(['user', 'company'])->where('token', $request->header('X-API-TOKEN'))->first())) { + if ($request->header('X-API-TOKEN') && ($company_token = CompanyToken::with([ + 'user' => [ + 'account', + ], 'company'])->where('token', $request->header('X-API-TOKEN'))->first())) { $user = $company_token->user; $error = [ @@ -51,7 +54,6 @@ class TokenAuth return response()->json($error, 403); } - /* | | Necessary evil here: As we are authenticating on CompanyToken, @@ -59,7 +61,6 @@ class TokenAuth | us to decouple a $user and their attached companies completely. | */ - $truth = app()->make(TruthSource::class); $truth->setCompanyUser($company_token->cu); diff --git a/app/Models/RecurringInvoice.php b/app/Models/RecurringInvoice.php index 953d2b2d89ca..e59a30da84e7 100644 --- a/app/Models/RecurringInvoice.php +++ b/app/Models/RecurringInvoice.php @@ -347,6 +347,10 @@ class RecurringInvoice extends BaseModel 'status', ]; + protected $with = [ + 'client.company', + ]; + protected $touches = []; public function getEntityType() diff --git a/app/Transformers/RecurringInvoiceTransformer.php b/app/Transformers/RecurringInvoiceTransformer.php index 5fcd576d89fe..5addf17b6aab 100644 --- a/app/Transformers/RecurringInvoiceTransformer.php +++ b/app/Transformers/RecurringInvoiceTransformer.php @@ -90,7 +90,6 @@ class RecurringInvoiceTransformer extends EntityTransformer 'po_number' => $invoice->po_number ?: '', 'date' => $invoice->date ?: '', 'last_sent_date' => $invoice->last_sent_date ?: '', - // 'next_send_date' => $invoice->next_send_date ?: '', 'next_send_date' => $invoice->next_send_date_client ?: '', 'due_date' => $invoice->due_date ?: '', 'terms' => $invoice->terms ?: '', From 82a6b2dbc0eafba7bc9c2b9dbea45e52d6e971fd Mon Sep 17 00:00:00 2001 From: David Bomba Date: Tue, 25 Apr 2023 07:13:33 +1000 Subject: [PATCH 2/9] Improve cancel url experience with Paypal --- .../PayPalExpressPaymentDriver.php | 9 +- lang/fr_CA/texts.php | 8 + lang/he/texts.php | 258 +++++++++--------- 3 files changed, 148 insertions(+), 127 deletions(-) diff --git a/app/PaymentDrivers/PayPalExpressPaymentDriver.php b/app/PaymentDrivers/PayPalExpressPaymentDriver.php index 94f2d0821201..779d77be0210 100644 --- a/app/PaymentDrivers/PayPalExpressPaymentDriver.php +++ b/app/PaymentDrivers/PayPalExpressPaymentDriver.php @@ -123,13 +123,18 @@ class PayPalExpressPaymentDriver extends BaseDriver { $this->initializeOmnipayGateway(); + dd('here'); + $response = $this->omnipay_gateway ->completePurchase(['amount' => $this->payment_hash->data->amount, 'currency' => $this->client->getCurrencyCode()]) ->send(); - if ($response->isCancelled()) { + if ($response->isCancelled() && $this->client->getSetting('enable_client_portal')) { return redirect()->route('client.invoices.index')->with('warning', ctrans('texts.status_cancelled')); } + elseif($response->isCancelled() && !$this->client->getSetting('enable_client_portal')){ + redirect()->route('client.invoices.show', ['invoice' => $this->payment_hash->fee_invoice])->with('warning', ctrans('texts.status_cancelled')); + } if ($response->isSuccessful()) { $data = [ @@ -195,7 +200,7 @@ class PayPalExpressPaymentDriver extends BaseDriver 'payment_hash' => $this->payment_hash->hash, 'payment_method_id' => GatewayType::PAYPAL, ]), - 'cancelUrl' => $this->client->company->domain().'/client/invoices', + 'cancelUrl' => $this->client->company->domain()."/client/invoices/{$invoice->hashed_id}", 'description' => implode(',', collect($this->payment_hash->data->invoices) ->map(function ($invoice) { return sprintf('%s: %s', ctrans('texts.invoice_number'), $invoice->invoice_number); diff --git a/lang/fr_CA/texts.php b/lang/fr_CA/texts.php index c15a08f77ca9..63b0b416e465 100644 --- a/lang/fr_CA/texts.php +++ b/lang/fr_CA/texts.php @@ -5054,6 +5054,14 @@ Lorsque les montant apparaîtront sur votre relevé, veuillez revenir sur cette 'here' => 'ici', 'industry_Restaurant & Catering' => 'Restauration et traiteur', 'show_credits_table' => 'Arricher la liste des crédits', + 'manual_payment' => 'Paiement manuel', + 'tax_summary_report' => 'Rapport sommaire de taxes', + 'tax_category' => 'Catégorie de taxe', + 'physical_goods' => 'Produits physiques', + 'digital_products' => 'Produits numériques', + 'services' => 'Services', + 'shipping' => 'Livraison', + 'tax_exempt' => 'Exemption de taxes', ); diff --git a/lang/he/texts.php b/lang/he/texts.php index 8683fd38ebdc..cceeb53b67a3 100644 --- a/lang/he/texts.php +++ b/lang/he/texts.php @@ -250,8 +250,8 @@ $LANG = array( חשבונית :חשבנוית של :סכום', 'notification_invoice_viewed' => 'העמית :עמית ראה את החשבנוית :חשבונית של :כמות.', - 'stripe_payment_text' => 'Invoice :invoicenumber for :amount for client :client', - 'stripe_payment_text_without_invoice' => 'Payment with no invoice for amount :amount for client :client', + 'stripe_payment_text' => 'חשבונית :invoicenumber עבור :amount עבור לקוח :client', + 'stripe_payment_text_without_invoice' => 'תשלום ללא חשבונית עבור סכום :amount עבור לקוח :client', 'reset_password' => 'אפשר לשחזר סיסמתך לחשבון בלחיצה הכפתור זה:', 'secure_payment' => 'תשלום מובטח', 'card_number' => 'מספר כרטיס', @@ -787,13 +787,13 @@ $LANG = array( 'activity_45' => ':user deleted task :task', 'activity_46' => ':user restored task :task', 'activity_47' => ':user updated expense :expense', - 'activity_48' => ':user created user :user', - 'activity_49' => ':user updated user :user', - 'activity_50' => ':user archived user :user', - 'activity_51' => ':user deleted user :user', - 'activity_52' => ':user restored user :user', - 'activity_53' => ':user marked sent :invoice', - 'activity_54' => ':user paid invoice :invoice', + 'activity_48' => ':user יצר את משתמש :user', + 'activity_49' => ':user עדכן את משתמש :user', + 'activity_50' => ':user הוסיף את משתמש :user לארכיון', + 'activity_51' => ':user מחק את משתמש :user', + 'activity_52' => ':user שחזר את משתמש :user', + 'activity_53' => ':user סימן את חשבונית :invoice כ-נשלחה', + 'activity_54' => ':user שילם את חשבונית :invoice', 'activity_55' => ':contact replied ticket :ticket', 'activity_56' => ':user viewed ticket :ticket', @@ -881,7 +881,7 @@ $LANG = array( 'custom_invoice_charges_helps' => 'הוסף שדה בעת יצירת חשבונית וכלול את החיוב בסיכומי הביניים של החשבונית.', 'token_expired' => 'פג תוקפו של אסימון האימות. בבקשה נסה שוב.', 'invoice_link' => 'קישור לחשבונית', - 'button_confirmation_message' => 'Confirm your email.', + 'button_confirmation_message' => 'תאמת את כתובת הדוא"ל שלך.', 'confirm' => 'אשר', 'email_preferences' => 'העדפות דוא"ל', 'created_invoices' => 'נוצר בהצלחה :count invoice(s)', @@ -995,7 +995,7 @@ $LANG = array( 'status_approved' => 'מאושר', 'quote_settings' => 'הגדרות הצעת מחיר', 'auto_convert_quote' => 'המרה אוטומטית', - 'auto_convert_quote_help' => 'Automatically convert a quote to an invoice when approved.', + 'auto_convert_quote_help' => 'המר הצעת מחיר לחשבונית באופן אוטומטי בעת אישור לקוח.', 'validate' => 'אמת', 'info' => 'פרטים', 'imported_expenses' => 'Successfully created :count_vendors vendor(s) and :count_expenses expense(s)', @@ -1180,7 +1180,7 @@ $LANG = array( 'plan_started' => 'Plan Started', 'plan_expires' => 'Plan Expires', - 'white_label_button' => 'Purchase White Label', + 'white_label_button' => 'קנה מיתוג "White Label"', 'pro_plan_year_description' => 'One year enrollment in the Invoice Ninja Pro Plan.', 'pro_plan_month_description' => 'One month enrollment in the Invoice Ninja Pro Plan.', @@ -2205,7 +2205,7 @@ $LANG = array( 'invalid_file' => 'סוג קובץ לא נתמך', 'add_documents_to_invoice' => 'הוסף מסמכים לחשבונית', 'mark_expense_paid' => 'סמן כשולם', - 'white_label_license_error' => 'Failed to validate the license, either expired or excessive activations. Email contact@invoiceninja.com for more information.', + 'white_label_license_error' => 'אימות הרשיון נכשל בגלל שפג התוקף או בשל כמות הפעלות חורגת. ניתן ליצור קשר עם contact@invoiceninja.com עבור עוד אינפורמציה.', 'plan_price' => 'Plan Price', 'wrong_confirmation' => 'Incorrect confirmation code', 'oauth_taken' => 'The account is already registered', @@ -2404,7 +2404,7 @@ $LANG = array( 'currency_vanuatu_vatu' => 'Vanuatu Vatu', 'currency_cuban_peso' => 'Cuban Peso', - 'currency_bz_dollar' => 'BZ Dollar', + 'currency_bz_dollar' => 'דולר בליזי', 'review_app_help' => 'We hope you\'re enjoying using the app.
If you\'d consider :link we\'d greatly appreciate it!', 'writing_a_review' => 'writing a review', @@ -2458,7 +2458,7 @@ $LANG = array( 'alipay' => 'Alipay', 'sofort' => 'Sofort', 'sepa' => 'SEPA Direct Debit', - 'name_without_special_characters' => 'Please enter a name with only the letters a-z and whitespaces', + 'name_without_special_characters' => 'נא להזין רק אותיות לועזיות a עד z ותווי רווח.', 'enable_alipay' => 'Accept Alipay', 'enable_sofort' => 'Accept EU bank transfers', 'stripe_alipay_help' => 'These gateways also need to be activated in :link.', @@ -2562,92 +2562,92 @@ $LANG = array( 'created_scheduled_report' => 'דוח תוזמן בהצלחה', 'deleted_scheduled_report' => 'דוח מתוזמן בוטל בהצלחה', 'scheduled_report_attached' => 'Your scheduled :type report is attached.', - 'scheduled_report_error' => 'Failed to create schedule report', - 'invalid_one_time_password' => 'Invalid one time password', + 'scheduled_report_error' => 'יצירת דו"ח לוח זמנים נכשל', + 'invalid_one_time_password' => 'סיסמה חד-פעמית שגויה', 'apple_pay' => 'Apple/Google Pay', 'enable_apple_pay' => 'Accept Apple Pay and Pay with Google', 'requires_subdomain' => 'This payment type requires that a :link.', - 'subdomain_is_set' => 'subdomain is set', - 'verification_file' => 'Verification File', - 'verification_file_missing' => 'The verification file is needed to accept payments.', + 'subdomain_is_set' => 'תת-שם המתחם הושם', + 'verification_file' => 'קובץ אימות', + 'verification_file_missing' => 'נדרש קובץ אימות על מנת לקבל תשלומים.', 'apple_pay_domain' => 'Use :domain as the domain in :link.', 'apple_pay_not_supported' => 'Sorry, Apple/Google Pay isn\'t supported by your browser', - 'optional_payment_methods' => 'Optional Payment Methods', + 'optional_payment_methods' => 'שיטות תשלום אופציונליות', 'add_subscription' => 'הוסף מנוי', - 'target_url' => 'Target', - 'target_url_help' => 'When the selected event occurs the app will post the entity to the target URL.', - 'event' => 'Event', - 'subscription_event_1' => 'Created Client', + 'target_url' => 'מטרה', + 'target_url_help' => 'האפליקציה תשלח את המידע אל target URL כשהאירוע הנבחר יקרה.', + 'event' => 'אירוע', + 'subscription_event_1' => 'לקוח נוצר', 'subscription_event_2' => 'חשבונית נוצרה', - 'subscription_event_3' => 'Created Quote', - 'subscription_event_4' => 'Created Payment', - 'subscription_event_5' => 'Created Vendor', - 'subscription_event_6' => 'Updated Quote', - 'subscription_event_7' => 'Deleted Quote', + 'subscription_event_3' => 'הצעת מחיר נוצרה', + 'subscription_event_4' => 'תשלום נוצר', + 'subscription_event_5' => 'ספק נוצר', + 'subscription_event_6' => 'הצעת מחיר עודכנה', + 'subscription_event_7' => 'הצעת מחיר נמחקה', 'subscription_event_8' => 'חשבונית עודכנה', 'subscription_event_9' => 'חשבונית נמחקה', - 'subscription_event_10' => 'Updated Client', - 'subscription_event_11' => 'Deleted Client', - 'subscription_event_12' => 'Deleted Payment', - 'subscription_event_13' => 'Updated Vendor', - 'subscription_event_14' => 'Deleted Vendor', - 'subscription_event_15' => 'Created Expense', - 'subscription_event_16' => 'Updated Expense', - 'subscription_event_17' => 'Deleted Expense', + 'subscription_event_10' => 'עדכן לקוח', + 'subscription_event_11' => 'מחק לקוח', + 'subscription_event_12' => 'מחק תשלום', + 'subscription_event_13' => 'עדכן ספק', + 'subscription_event_14' => 'מחק ספק', + 'subscription_event_15' => 'צור הוצאה', + 'subscription_event_16' => 'עדכן הוצאה', + 'subscription_event_17' => 'מחק הוצאה', 'subscription_event_18' => 'צור משימה', 'subscription_event_19' => 'עדכן משימה', 'subscription_event_20' => 'מחק משימה', - 'subscription_event_21' => 'Approved Quote', - 'subscriptions' => 'Subscriptions', - 'updated_subscription' => 'Successfully updated subscription', - 'created_subscription' => 'Successfully created subscription', - 'edit_subscription' => 'Edit Subscription', - 'archive_subscription' => 'Archive Subscription', - 'archived_subscription' => 'Successfully archived subscription', - 'project_error_multiple_clients' => 'The projects can\'t belong to different clients', + 'subscription_event_21' => 'אישור הצעת מחיר', + 'subscriptions' => 'מנויים', + 'updated_subscription' => 'מנוי עודכן בהצלחה', + 'created_subscription' => 'מנוי נוצר בהצלחה', + 'edit_subscription' => 'ערוך מנוי', + 'archive_subscription' => 'מנויים פעילים', + 'archived_subscription' => 'מנוי הועבר לארכיון בהצלחה', + 'project_error_multiple_clients' => 'הפרויקט אינו יכול להיות משויך ללקוח שונה', 'invoice_project' => 'פרויקט חשבונית', 'module_recurring_invoice' => 'חשבוניות מחזוריות', - 'module_credit' => 'Credits', - 'module_quote' => 'Quotes & Proposals', + 'module_credit' => 'אשראי / יתרה', + 'module_quote' => 'הצעות מחיר', 'module_task' => 'משימות ופרויקטים', - 'module_expense' => 'Expenses & Vendors', - 'module_ticket' => 'Tickets', - 'reminders' => 'Reminders', - 'send_client_reminders' => 'Send email reminders', + 'module_expense' => 'הוצאות וספקים', + 'module_ticket' => 'כרטיסיות', + 'reminders' => 'תזכורות', + 'send_client_reminders' => 'שלח תזכורות בדוא"ל', 'can_view_tasks' => 'משימות מוצגות בפורטל', - 'is_not_sent_reminders' => 'Reminders are not sent', + 'is_not_sent_reminders' => 'תזכורות לא נשלחו', 'promotion_footer' => 'Your promotion will expire soon, :link to upgrade now.', 'unable_to_delete_primary' => 'Note: to delete this company first delete all linked companies.', - 'please_register' => 'Please register your account', - 'processing_request' => 'Processing request', + 'please_register' => 'נא להירשם', + 'processing_request' => 'מעבד בקשה', 'mcrypt_warning' => 'Warning: Mcrypt is deprecated, run :command to update your cipher.', 'edit_times' => 'Edit Times', 'inclusive_taxes_help' => 'Include taxes in the cost', 'inclusive_taxes_notice' => 'לא ניתן לשנות הגדרה זו לאחר יצירת חשבונית.', 'inclusive_taxes_warning' => 'אזהרה: יהיה צורך לשמור מחדש חשבוניות קיימות', - 'copy_shipping' => 'Copy Shipping', - 'copy_billing' => 'Copy Billing', - 'quote_has_expired' => 'The quote has expired, please contact the merchant.', + 'copy_shipping' => 'העתק פרטי משלוח', + 'copy_billing' => 'העתק פרטי חשבון', + 'quote_has_expired' => 'פג תוקף הצעת המחיר, אנא צור קשר עם התמיכה.', 'empty_table_footer' => 'Showing 0 to 0 of 0 entries', - 'do_not_trust' => 'Do not remember this device', - 'trust_for_30_days' => 'Trust for 30 days', - 'trust_forever' => 'Trust forever', + 'do_not_trust' => 'לא לזכור את מכשיר זה', + 'trust_for_30_days' => 'זכור מכשיר זה ל-30 יום', + 'trust_forever' => 'זכור מכשיר זה', 'kanban' => 'Kanban', - 'backlog' => 'Backlog', - 'ready_to_do' => 'Ready to do', + 'backlog' => 'פיגורים', + 'ready_to_do' => 'מוכן לביצוע', 'in_progress' => 'בתהליך', - 'add_status' => 'Add status', + 'add_status' => 'הוסף סטטוס', 'archive_status' => 'Archive Status', - 'new_status' => 'New Status', - 'convert_products' => 'Convert Products', - 'convert_products_help' => 'Automatically convert product prices to the client\'s currency', + 'new_status' => 'סטטוס חדש', + 'convert_products' => 'המר מוצר', + 'convert_products_help' => 'המר אוטומטית את מחירי המוצרים למטבע הלקוח', 'improve_client_portal_link' => 'Set a subdomain to shorten the client portal link.', - 'budgeted_hours' => 'Budgeted Hours', - 'progress' => 'Progress', + 'budgeted_hours' => 'שעות בתקציב', + 'progress' => 'התקדמות', 'view_project' => 'צפה בפרוייקט', 'summary' => 'סיכום', - 'endless_reminder' => 'Endless Reminder', - 'signature_on_invoice_help' => 'Add the following code to show your client\'s signature on the PDF.', + 'endless_reminder' => 'תזכורת קבועה', + 'signature_on_invoice_help' => 'הוסף את הקוד הבא כדי להציג את החתימה של הלקוח שלך ב-PDF.', 'signature_on_pdf' => 'פתח בPDF', 'signature_on_pdf_help' => 'הצג את חתימת הלקוח ב-PDF של החשבונית/הצעת המחיר.', 'expired_white_label' => 'The white label license has expired', @@ -2657,42 +2657,42 @@ $LANG = array( 'custom_fields_tip' => 'Use Label|Option1,Option2 to show a select box.', 'client_information' => 'פרטי לקוח', 'updated_client_details' => 'פרטי לקוח עודכנו בהצלחה', - 'auto' => 'Auto', + 'auto' => 'אוטומטי', 'tax_amount' => 'סכום מס', 'tax_paid' => 'מס ששולם', - 'none' => 'None', + 'none' => 'ללא', 'proposal_message_button' => 'To view your proposal for :amount, click the button below.', 'proposal' => 'הצעה', 'proposals' => 'הצעות', - 'list_proposals' => 'List Proposals', + 'list_proposals' => 'הצג רשימת הצעות', 'new_proposal' => 'הצעה חדשה', 'edit_proposal' => 'ערוך הצעה', 'archive_proposal' => 'העבר פרויקט לארכיון', 'delete_proposal' => 'מחר הצעה', - 'created_proposal' => 'Successfully created proposal', - 'updated_proposal' => 'Successfully updated proposal', - 'archived_proposal' => 'Successfully archived proposal', - 'deleted_proposal' => 'Successfully archived proposal', + 'created_proposal' => 'הצעת נוצרה בהצלחה', + 'updated_proposal' => 'הצעת עודכנה בהצלחה', + 'archived_proposal' => 'הצעה הועברה לארכיון בהצלחה', + 'deleted_proposal' => 'הצעה הועברה לארכיון בהצלחה', 'archived_proposals' => 'Successfully archived :count proposals', 'deleted_proposals' => 'Successfully archived :count proposals', - 'restored_proposal' => 'Successfully restored proposal', - 'restore_proposal' => 'Restore Proposal', - 'snippet' => 'Snippet', - 'snippets' => 'Snippets', - 'proposal_snippet' => 'Snippet', - 'proposal_snippets' => 'Snippets', - 'new_proposal_snippet' => 'New Snippet', - 'edit_proposal_snippet' => 'Edit Snippet', - 'archive_proposal_snippet' => 'Archive Snippet', - 'delete_proposal_snippet' => 'Delete Snippet', - 'created_proposal_snippet' => 'Successfully created snippet', - 'updated_proposal_snippet' => 'Successfully updated snippet', - 'archived_proposal_snippet' => 'Successfully archived snippet', - 'deleted_proposal_snippet' => 'Successfully archived snippet', + 'restored_proposal' => 'הצעת שוחזרה בהצלחה', + 'restore_proposal' => 'שחזר הצעה', + 'snippet' => 'מקטע', + 'snippets' => 'מקטעים', + 'proposal_snippet' => 'מקטע', + 'proposal_snippets' => 'מקטעים', + 'new_proposal_snippet' => 'מקטע חדש', + 'edit_proposal_snippet' => 'ערוך מקטע', + 'archive_proposal_snippet' => 'העברת מקטע לארכיון', + 'delete_proposal_snippet' => 'מחיקת מקטע', + 'created_proposal_snippet' => 'מקטע נוצר בהצלחה', + 'updated_proposal_snippet' => 'מקטע עודכן בהצלחה', + 'archived_proposal_snippet' => 'מקטע הועבר לארכיון', + 'deleted_proposal_snippet' => 'מקטע הועבר לארכיון', 'archived_proposal_snippets' => 'Successfully archived :count snippets', 'deleted_proposal_snippets' => 'Successfully archived :count snippets', - 'restored_proposal_snippet' => 'Successfully restored snippet', - 'restore_proposal_snippet' => 'Restore Snippet', + 'restored_proposal_snippet' => 'מקטע שוחזר', + 'restore_proposal_snippet' => 'שחזר מקטע', 'template' => 'Template', 'templates' => 'Templates', 'proposal_template' => 'Template', @@ -2709,12 +2709,12 @@ $LANG = array( 'deleted_proposal_templates' => 'Successfully archived :count templates', 'restored_proposal_template' => 'Successfully restored template', 'restore_proposal_template' => 'Restore Template', - 'proposal_category' => 'Category', - 'proposal_categories' => 'Categories', - 'new_proposal_category' => 'New Category', - 'edit_proposal_category' => 'Edit Category', - 'archive_proposal_category' => 'Archive Category', - 'delete_proposal_category' => 'Delete Category', + 'proposal_category' => 'קטגוריה', + 'proposal_categories' => 'קטגוריות', + 'new_proposal_category' => 'קטגוריה חדשה', + 'edit_proposal_category' => 'ערוך קטגוריה', + 'archive_proposal_category' => 'העבר קטגוריה לארכיון', + 'delete_proposal_category' => 'מחיקת קטגוריה', 'created_proposal_category' => 'Successfully created category', 'updated_proposal_category' => 'Successfully updated category', 'archived_proposal_category' => 'Successfully archived category', @@ -2722,42 +2722,42 @@ $LANG = array( 'archived_proposal_categories' => 'Successfully archived :count categories', 'deleted_proposal_categories' => 'Successfully archived :count categories', 'restored_proposal_category' => 'Successfully restored category', - 'restore_proposal_category' => 'Restore Category', - 'delete_status' => 'Delete Status', - 'standard' => 'Standard', - 'icon' => 'Icon', - 'proposal_not_found' => 'The requested proposal is not available', - 'create_proposal_category' => 'Create category', - 'clone_proposal_template' => 'Clone Template', - 'proposal_email' => 'Proposal Email', + 'restore_proposal_category' => 'שחזר קטגוריה', + 'delete_status' => 'מחק סטטוס', + 'standard' => 'רגיל', + 'icon' => 'אייקון', + 'proposal_not_found' => 'ההצעה המבוקשת לא נמצאה', + 'create_proposal_category' => 'יצירת קטגוריה', + 'clone_proposal_template' => 'שכפול טמפלט', + 'proposal_email' => 'דוא"ל להצעה', 'proposal_subject' => 'New proposal :number from :account', 'proposal_message' => 'To view your proposal for :amount, click the link below.', - 'emailed_proposal' => 'Successfully emailed proposal', - 'load_template' => 'Load Template', - 'no_assets' => 'No images, drag to upload', - 'add_image' => 'Add Image', - 'select_image' => 'Select Image', + 'emailed_proposal' => 'הצעה נשלחה בדוא"ל', + 'load_template' => 'שימוש בתבנית', + 'no_assets' => 'אין תמונה, גרור תמונות להעלאה ', + 'add_image' => 'הוספת תמונה', + 'select_image' => 'בחירת תמונה', 'upgrade_to_upload_images' => 'Upgrade to the enterprise plan to upload images', - 'delete_image' => 'Delete Image', - 'delete_image_help' => 'Warning: deleting the image will remove it from all proposals.', + 'delete_image' => 'מחיקת תמונה', + 'delete_image_help' => 'אזהרה: מחיקת התמונה תסיר אותה מכל ההצעות.', 'amount_variable_help' => 'Note: the invoice $amount field will use the partial/deposit field if set otherwise it will use the invoice balance.', - 'taxes_are_included_help' => 'Note: Inclusive taxes have been enabled.', - 'taxes_are_not_included_help' => 'Note: Inclusive taxes are not enabled.', + 'taxes_are_included_help' => 'הערה: הופעלו מסים כוללים.', + 'taxes_are_not_included_help' => 'הערה: מסים כוללים לא הופעלו.', 'change_requires_purge' => 'Changing this setting requires :link the account data.', 'purging' => 'purging', 'warning_local_refund' => 'The refund will be recorded in the app but will NOT be processed by the payment gateway.', - 'email_address_changed' => 'Email address has been changed', + 'email_address_changed' => 'כתובת דוא"ל שונתה', 'email_address_changed_message' => 'The email address for your account has been changed from :old_email to :new_email.', - 'test' => 'Test', - 'beta' => 'Beta', + 'test' => 'ניסוי', + 'beta' => 'בטא', 'gmp_required' => 'Exporting to ZIP requires the GMP extension', - 'email_history' => 'Email History', + 'email_history' => 'היסטוריית דוא"ל', 'loading' => 'טוען', - 'no_messages_found' => 'No messages found', + 'no_messages_found' => 'לא נמצאו הודעות', 'processing' => 'מעבד', - 'reactivate' => 'Reactivate', - 'reactivated_email' => 'The email address has been reactivated', - 'emails' => 'Emails', + 'reactivate' => 'הפעל שוב', + 'reactivated_email' => 'כתובת הדוא"ל הופעלה מחדש', + 'emails' => 'דואר אלקטרוני', 'opened' => 'Opened', 'bounced' => 'Bounced', 'total_sent' => 'Total Sent', @@ -5054,6 +5054,14 @@ $LANG = array( 'here' => 'here', 'industry_Restaurant & Catering' => 'Restaurant & Catering', 'show_credits_table' => 'Show Credits Table', + 'manual_payment' => 'Payment Manual', + 'tax_summary_report' => 'Tax Summary Report', + 'tax_category' => 'Tax Category', + 'physical_goods' => 'Physical Goods', + 'digital_products' => 'Digital Products', + 'services' => 'Services', + 'shipping' => 'Shipping', + 'tax_exempt' => 'Tax Exempt', ); From 1bcb76a63a63576c648de29c3af981d965ff6d41 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Tue, 25 Apr 2023 07:52:54 +1000 Subject: [PATCH 3/9] Improved error page handling --- resources/views/errors/guest.blade.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/resources/views/errors/guest.blade.php b/resources/views/errors/guest.blade.php index 0b2500ba8319..f1cf00ec361b 100644 --- a/resources/views/errors/guest.blade.php +++ b/resources/views/errors/guest.blade.php @@ -1,5 +1,5 @@ @extends('portal.ninja2020.layout.error') -@section('title', __($title) ?: 'Server Error') -@section('code', __($code) ?: '500') -@section('message', __($message) ?: 'System Error') +@section('title', __($title) ?? 'Server Error') +@section('code', __($code) ?? '500') +@section('message', __($message) ?? 'System Error') From d8a4994e202568c38b62ae83b71110d0ebd99b14 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Tue, 25 Apr 2023 08:06:27 +1000 Subject: [PATCH 4/9] Add in verification view for gocardless --- app/PaymentDrivers/GoCardless/DirectDebit.php | 2 +- app/PaymentDrivers/GoCardlessPaymentDriver.php | 5 +++++ .../ninja2020/gateways/gocardless/verification.blade.php | 7 +++++++ 3 files changed, 13 insertions(+), 1 deletion(-) create mode 100644 resources/views/portal/ninja2020/gateways/gocardless/verification.blade.php diff --git a/app/PaymentDrivers/GoCardless/DirectDebit.php b/app/PaymentDrivers/GoCardless/DirectDebit.php index 81bb8c105b78..c7e6d04b0876 100644 --- a/app/PaymentDrivers/GoCardless/DirectDebit.php +++ b/app/PaymentDrivers/GoCardless/DirectDebit.php @@ -143,7 +143,7 @@ class DirectDebit implements MethodInterface /** * Handle unsuccessful authorization. * - * @param Exception $exception + * @param \Exception $exception * @throws PaymentFailed * @return void */ diff --git a/app/PaymentDrivers/GoCardlessPaymentDriver.php b/app/PaymentDrivers/GoCardlessPaymentDriver.php index 433ab7230f33..25977caaf33b 100644 --- a/app/PaymentDrivers/GoCardlessPaymentDriver.php +++ b/app/PaymentDrivers/GoCardlessPaymentDriver.php @@ -542,4 +542,9 @@ class GoCardlessPaymentDriver extends BaseDriver return $client; } + + public function verificationView() + { + return render('gateways.gocardless.verification'); + } } diff --git a/resources/views/portal/ninja2020/gateways/gocardless/verification.blade.php b/resources/views/portal/ninja2020/gateways/gocardless/verification.blade.php new file mode 100644 index 000000000000..284ac4c2b51d --- /dev/null +++ b/resources/views/portal/ninja2020/gateways/gocardless/verification.blade.php @@ -0,0 +1,7 @@ +@extends('portal.ninja2020.layout.payments', ['gateway_title' => ctrans('texts.payment_type_gocardless'), 'card_title' => ctrans('texts.complete_verification')]) + +@section('gateway_content') + @component('portal.ninja2020.components.general.card-element-single') + This payment method is still in a pending state and has not yet been verified. Please contact your vendor for more information. + @endcomponent +@endsection From fa1f16f36daf23da18e0afb29b848d845dd99e12 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Tue, 25 Apr 2023 08:31:24 +1000 Subject: [PATCH 5/9] Remove oauth credentials as fillable properties --- app/Http/Controllers/Auth/LoginController.php | 16 ++++++++++++---- .../Controllers/ConnectedAccountController.php | 9 ++++++--- app/Models/User.php | 1 + 3 files changed, 19 insertions(+), 7 deletions(-) diff --git a/app/Http/Controllers/Auth/LoginController.php b/app/Http/Controllers/Auth/LoginController.php index 8ae2803a2742..ee81a02676bc 100644 --- a/app/Http/Controllers/Auth/LoginController.php +++ b/app/Http/Controllers/Auth/LoginController.php @@ -649,11 +649,15 @@ class LoginController extends BaseController 'email' => $socialite_user->getEmail(), 'oauth_user_id' => $socialite_user->getId(), 'oauth_provider_id' => $provider, - 'oauth_user_token' => $oauth_user_token, - 'oauth_user_refresh_token' => $socialite_user->refreshToken, + // 'oauth_user_token' => $oauth_user_token, + // 'oauth_user_refresh_token' => $socialite_user->refreshToken, ]; $user->update($update_user); + $user->oauth_user_token = $oauth_user_token; + $user->oauth_user_refresh_token = $socialite_user->refreshToken; + $user->save(); + } else { nlog('user not found for oauth'); } @@ -679,12 +683,16 @@ class LoginController extends BaseController 'email' => $socialite_user->getEmail(), 'oauth_user_id' => $socialite_user->getId(), 'oauth_provider_id' => $provider, - 'oauth_user_token' => $oauth_user_token, - 'oauth_user_refresh_token' => $socialite_user->accessTokenResponseBody['refresh_token'], + // 'oauth_user_token' => $oauth_user_token, + // 'oauth_user_refresh_token' => $socialite_user->accessTokenResponseBody['refresh_token'], 'oauth_user_token_expiry' => $oauth_expiry, ]; $user->update($update_user); + $user->oauth_user_refresh_token = $socialite_user->accessTokenResponseBody['refresh_token']; + $user->oauth_user_token = $oauth_user_token; + $user->save(); + } else { nlog('user not found for oauth'); } diff --git a/app/Http/Controllers/ConnectedAccountController.php b/app/Http/Controllers/ConnectedAccountController.php index 94a75fccf9ec..c93d05477935 100644 --- a/app/Http/Controllers/ConnectedAccountController.php +++ b/app/Http/Controllers/ConnectedAccountController.php @@ -203,10 +203,10 @@ class ConnectedAccountController extends BaseController $connected_account = [ 'email' => $google->harvestEmail($user), 'oauth_user_id' => $google->harvestSubField($user), - 'oauth_user_token' => $token, - 'oauth_user_refresh_token' => $refresh_token, + // 'oauth_user_token' => $token, + // 'oauth_user_refresh_token' => $refresh_token, 'oauth_provider_id' => 'google', - 'email_verified_at' =>now(), + // 'email_verified_at' =>now(), ]; if (auth()->user()->email != $google->harvestEmail($user)) { @@ -215,6 +215,9 @@ class ConnectedAccountController extends BaseController auth()->user()->update($connected_account); auth()->user()->email_verified_at = now(); + auth()->user()->oauth_user_token = $token; + auth()->user()->oauth_user_refresh_token = $refresh_token; + auth()->user()->save(); $this->activateGmail(auth()->user()); diff --git a/app/Models/User.php b/app/Models/User.php index 8ed7804f89ff..e3e68c9b4a87 100644 --- a/app/Models/User.php +++ b/app/Models/User.php @@ -258,6 +258,7 @@ class User extends Authenticatable implements MustVerifyEmail 'custom_value4', 'is_deleted', 'oauth_user_token', + 'oauth_user_refresh_token', ]; /** From 9f96c2866d14a4d00a85f45166dc3c448f4f7086 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Tue, 25 Apr 2023 08:35:04 +1000 Subject: [PATCH 6/9] Remove oauth credentials as fillable properties --- app/Models/User.php | 4 ++-- app/PaymentDrivers/GoCardlessPaymentDriver.php | 3 --- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/app/Models/User.php b/app/Models/User.php index e3e68c9b4a87..729b531be509 100644 --- a/app/Models/User.php +++ b/app/Models/User.php @@ -257,8 +257,8 @@ class User extends Authenticatable implements MustVerifyEmail 'custom_value3', 'custom_value4', 'is_deleted', - 'oauth_user_token', - 'oauth_user_refresh_token', + // 'oauth_user_token', + // 'oauth_user_refresh_token', ]; /** diff --git a/app/PaymentDrivers/GoCardlessPaymentDriver.php b/app/PaymentDrivers/GoCardlessPaymentDriver.php index 25977caaf33b..2a251a5b5822 100644 --- a/app/PaymentDrivers/GoCardlessPaymentDriver.php +++ b/app/PaymentDrivers/GoCardlessPaymentDriver.php @@ -385,9 +385,6 @@ class GoCardlessPaymentDriver extends BaseDriver ); } - - - public function ensureMandateIsReady($token) { try { From 5ae49725830bff16aad8165dd61dbcf998a139a6 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Tue, 25 Apr 2023 08:37:39 +1000 Subject: [PATCH 7/9] Add minimal padding for logos in designs --- resources/views/email/template/client.blade.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/resources/views/email/template/client.blade.php b/resources/views/email/template/client.blade.php index d99d69d3dd76..4d9462b2b370 100644 --- a/resources/views/email/template/client.blade.php +++ b/resources/views/email/template/client.blade.php @@ -142,14 +142,14 @@ style="border: 1px solid #c2c2c2;" class="dark-bg-base"> -
+
@if($logo && strpos($logo, 'blank.png') === false)  @endif From 86585d5c8ebaed268a7179af9acb4597a68cd31c Mon Sep 17 00:00:00 2001 From: David Bomba Date: Tue, 25 Apr 2023 09:29:39 +1000 Subject: [PATCH 8/9] Gracefully redirect to the appropriate front end --- app/Http/Controllers/Auth/LoginController.php | 61 +++++++++++-------- 1 file changed, 36 insertions(+), 25 deletions(-) diff --git a/app/Http/Controllers/Auth/LoginController.php b/app/Http/Controllers/Auth/LoginController.php index ee81a02676bc..891172bcbc54 100644 --- a/app/Http/Controllers/Auth/LoginController.php +++ b/app/Http/Controllers/Auth/LoginController.php @@ -12,34 +12,35 @@ namespace App\Http\Controllers\Auth; +use Google_Client; +use App\Models\User; +use App\Utils\Ninja; +use App\Models\Account; +use App\Libraries\MultiDB; +use App\Utils\TruthSource; +use Microsoft\Graph\Model; +use App\Models\CompanyUser; +use App\Models\CompanyToken; +use Illuminate\Http\Request; +use App\Libraries\OAuth\OAuth; +use App\Events\User\UserLoggedIn; +use PragmaRX\Google2FA\Google2FA; +use App\Jobs\Account\CreateAccount; +use Illuminate\Support\Facades\Auth; +use App\Utils\Traits\User\LoginCache; +use Illuminate\Support\Facades\Cache; +use Turbo124\Beacon\Facades\LightLogs; +use App\Http\Controllers\BaseController; +use App\Jobs\Company\CreateCompanyToken; +use Laravel\Socialite\Facades\Socialite; +use App\Http\Requests\Login\LoginRequest; +use App\Libraries\OAuth\Providers\Google; +use Illuminate\Database\Eloquent\Builder; use App\DataMapper\Analytics\LoginFailure; use App\DataMapper\Analytics\LoginSuccess; -use App\Events\User\UserLoggedIn; -use App\Http\Controllers\BaseController; -use App\Http\Requests\Login\LoginRequest; -use App\Jobs\Account\CreateAccount; -use App\Jobs\Company\CreateCompanyToken; -use App\Libraries\MultiDB; -use App\Libraries\OAuth\OAuth; -use App\Libraries\OAuth\Providers\Google; -use App\Models\Account; -use App\Models\CompanyToken; -use App\Models\CompanyUser; -use App\Models\User; -use App\Transformers\CompanyUserTransformer; -use App\Utils\Ninja; -use App\Utils\Traits\User\LoginCache; use App\Utils\Traits\UserSessionAttributes; -use App\Utils\TruthSource; -use Google_Client; -use Illuminate\Database\Eloquent\Builder; +use App\Transformers\CompanyUserTransformer; use Illuminate\Foundation\Auth\AuthenticatesUsers; -use Illuminate\Http\Request; -use Illuminate\Support\Facades\Auth; -use Laravel\Socialite\Facades\Socialite; -use Microsoft\Graph\Model; -use PragmaRX\Google2FA\Google2FA; -use Turbo124\Beacon\Facades\LightLogs; class LoginController extends BaseController { @@ -610,6 +611,9 @@ class LoginController extends BaseController $parameters = ['response_type' => 'code', 'redirect_uri' => config('ninja.app_url') . "/auth/microsoft"]; } + if(request()->hasHeader('X-REACT')) + Cache::put("react_redir:".auth()->user()->account->key, 'true', 300); + if (request()->has('code')) { return $this->handleProviderCallback($provider); } else { @@ -662,7 +666,14 @@ class LoginController extends BaseController nlog('user not found for oauth'); } - return redirect('/#/'); + $redirect_url = '/#/'; + + $request_from_react = Cache::pull("react_redir:".auth()->user()->account->key); + + if($request_from_react) + $redirect_url = 'https://app.invoicing.co/#/settings/user_details/connect'; + + return redirect($redirect_url); } public function handleMicrosoftProviderCallback($provider = 'microsoft') From a71e8bd5e006eb17e1e8b29d9ad64b8948be6086 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Tue, 25 Apr 2023 09:31:58 +1000 Subject: [PATCH 9/9] Add in verification view for gocardless --- app/Http/Controllers/Auth/LoginController.php | 2 +- config/ninja.php | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/app/Http/Controllers/Auth/LoginController.php b/app/Http/Controllers/Auth/LoginController.php index 891172bcbc54..fbad5f88b741 100644 --- a/app/Http/Controllers/Auth/LoginController.php +++ b/app/Http/Controllers/Auth/LoginController.php @@ -671,7 +671,7 @@ class LoginController extends BaseController $request_from_react = Cache::pull("react_redir:".auth()->user()->account->key); if($request_from_react) - $redirect_url = 'https://app.invoicing.co/#/settings/user_details/connect'; + $redirect_url = config('ninja.react_url')."/#/settings/user_details/connect"; return redirect($redirect_url); } diff --git a/config/ninja.php b/config/ninja.php index 0d6870142ed6..b7823016323c 100644 --- a/config/ninja.php +++ b/config/ninja.php @@ -5,6 +5,7 @@ return [ 'web_url' => 'https://www.invoiceninja.com', 'admin_token' => env('NINJA_ADMIN_TOKEN', ''), 'license_url' => 'https://app.invoiceninja.com', + 'react_url' => 'https://app.invoicing.co', 'production' => env('NINJA_PROD', false), 'license' => env('NINJA_LICENSE', ''), 'version_url' => 'https://pdf.invoicing.co/api/version',