From 23d9a2728bd6ae6e6c1d2c1710e9fcc27a2c201d Mon Sep 17 00:00:00 2001 From: Patrick Samson Date: Thu, 18 Jun 2015 19:28:43 -0400 Subject: [PATCH 01/58] Fix Charts & Reports queries using SQLite --- app/Http/Controllers/ReportController.php | 78 +++++++++++++++++------ 1 file changed, 58 insertions(+), 20 deletions(-) diff --git a/app/Http/Controllers/ReportController.php b/app/Http/Controllers/ReportController.php index b1746761b10f..50a529a701ba 100644 --- a/app/Http/Controllers/ReportController.php +++ b/app/Http/Controllers/ReportController.php @@ -1,6 +1,7 @@ balance; } - if ($action == 'export') { + if ($action == 'export') + { self::export($exportData, $reportTotals); } } - if ($enableChart) { - foreach ([ENTITY_INVOICE, ENTITY_PAYMENT, ENTITY_CREDIT] as $entityType) { - $records = DB::table($entityType.'s') - ->select(DB::raw('sum(amount) as total, concat(YEAR('.$entityType.'_date), '.$groupBy.'('.$entityType.'_date)) as '.$groupBy)) - ->where('account_id', '=', Auth::user()->account_id) - ->where($entityType.'s.is_deleted', '=', false) - ->where($entityType.'s.'.$entityType.'_date', '>=', $startDate->format('Y-m-d')) - ->where($entityType.'s.'.$entityType.'_date', '<=', $endDate->format('Y-m-d')) - ->groupBy($groupBy); + if ($enableChart) + { + foreach ([ENTITY_INVOICE, ENTITY_PAYMENT, ENTITY_CREDIT] as $entityType) + { + // SQLite does not support the YEAR(), MONTH(), WEEK() and similar functions. + // Let's see if SQLite is being used. + if (Config::get('database.connections.'.Config::get('database.default').'.driver') == 'sqlite') + { + // Replace the unsupported function with it's date format counterpart + switch ($groupBy) + { + case 'MONTH': + $dateFormat = '%m'; // returns 01-12 + break; + case 'WEEK': + $dateFormat = '%W'; // returns 00-53 + break; + case 'DAYOFYEAR': + $dateFormat = '%j'; // returns 001-366 + break; + default: + $dateFormat = '%m'; // MONTH by default + break; + } - if ($entityType == ENTITY_INVOICE) { + // Concatenate the year and the chosen timeframe (Month, Week or Day) + $timeframe = 'strftime("%Y", '.$entityType.'_date) || strftime("'.$dateFormat.'", '.$entityType.'_date)'; + } + else + { + // Supported by Laravel's other DBMS drivers (MySQL, MSSQL and PostgreSQL) + $timeframe = 'concat(YEAR('.$entityType.'_date), '.$groupBy.'('.$entityType.'_date))'; + } + + $records = DB::table($entityType.'s') + ->select(DB::raw('sum(amount) as total, '.$timeframe.' as '.$groupBy)) + ->where('account_id', '=', Auth::user()->account_id) + ->where($entityType.'s.is_deleted', '=', false) + ->where($entityType.'s.'.$entityType.'_date', '>=', $startDate->format('Y-m-d')) + ->where($entityType.'s.'.$entityType.'_date', '<=', $endDate->format('Y-m-d')) + ->groupBy($groupBy); + + if ($entityType == ENTITY_INVOICE) + { $records->where('is_quote', '=', false) ->where('is_recurring', '=', false); } $totals = $records->lists('total'); - $dates = $records->lists($groupBy); - $data = array_combine($dates, $totals); + $dates = $records->lists($groupBy); + $data = array_combine($dates, $totals); $padding = $groupBy == 'DAYOFYEAR' ? 'day' : ($groupBy == 'WEEK' ? 'week' : 'month'); $endDate->modify('+1 '.$padding); $interval = new DateInterval('P1'.substr($groupBy, 0, 1)); - $period = new DatePeriod($startDate, $interval, $endDate); + $period = new DatePeriod($startDate, $interval, $endDate); $endDate->modify('-1 '.$padding); $totals = []; - foreach ($period as $d) { + foreach ($period as $d) + { $dateFormat = $groupBy == 'DAYOFYEAR' ? 'z' : ($groupBy == 'WEEK' ? 'W' : 'n'); $date = $d->format('Y'.$dateFormat); $totals[] = isset($data[$date]) ? $data[$date] : 0; - - if ($entityType == ENTITY_INVOICE) { + + if ($entityType == ENTITY_INVOICE) + { $labelFormat = $groupBy == 'DAYOFYEAR' ? 'j' : ($groupBy == 'WEEK' ? 'W' : 'F'); - $label = $d->format($labelFormat); + $label = $d->format($labelFormat); $labels[] = $label; } } - + $max = max($totals); - if ($max > 0) { + if ($max > 0) + { $datasets[] = [ 'totals' => $totals, 'colors' => $entityType == ENTITY_INVOICE ? '78,205,196' : ($entityType == ENTITY_CREDIT ? '199,244,100' : '255,107,107'), From 813b169006efb9069689aedee86881d0d36e6425 Mon Sep 17 00:00:00 2001 From: Patrick Samson Date: Thu, 18 Jun 2015 19:30:41 -0400 Subject: [PATCH 02/58] Fixed format_money() with empty string as value --- app/Libraries/Utils.php | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/app/Libraries/Utils.php b/app/Libraries/Utils.php index 94025347fcda..3ac30c47b5e5 100644 --- a/app/Libraries/Utils.php +++ b/app/Libraries/Utils.php @@ -251,6 +251,10 @@ class Utils $currency = Currency::find(1); } + if (!$value) { + $value = 0; + } + Cache::add('currency', $currency, DEFAULT_QUERY_CACHE); return $currency->symbol.number_format($value, $currency->precision, $currency->decimal_separator, $currency->thousand_separator); @@ -352,7 +356,7 @@ class Utils $timezone = Session::get(SESSION_TIMEZONE, DEFAULT_TIMEZONE); $format = Session::get(SESSION_DATETIME_FORMAT, DEFAULT_DATETIME_FORMAT); - + $dateTime = DateTime::createFromFormat('Y-m-d H:i:s', $date); $dateTime->setTimeZone(new DateTimeZone($timezone)); From 8b52cd10691951d4dde1d689b57140acb04e3e7e Mon Sep 17 00:00:00 2001 From: Patrick Samson Date: Thu, 18 Jun 2015 19:58:06 -0400 Subject: [PATCH 03/58] Improved French translation --- resources/lang/fr/texts.php | 44 ++++++------- resources/lang/fr_CA/texts.php | 112 ++++++++++++++++----------------- 2 files changed, 78 insertions(+), 78 deletions(-) diff --git a/resources/lang/fr/texts.php b/resources/lang/fr/texts.php index 010c5557709c..8ded07fc32f4 100644 --- a/resources/lang/fr/texts.php +++ b/resources/lang/fr/texts.php @@ -1,4 +1,4 @@ - 'Facture #', 'po_number' => 'Numéro du bon de commande', 'po_number_short' => 'Bon de commande #', - 'frequency_id' => 'Fréquence', + 'frequency_id' => 'Fréquence', 'discount' => 'Remise', 'taxes' => 'Taxes', 'tax' => 'Taxe', - 'item' => 'Article', + 'item' => 'Article', 'description' => 'Description', 'unit_cost' => 'Coût unitaire', 'quantity' => 'Quantité', @@ -117,11 +117,11 @@ return array( 'billed_client' => 'client facturé', 'billed_clients' => 'clients facturés', 'active_client' => 'client actif', - 'active_clients' => 'clients actifs', + 'active_clients' => 'clients actifs', 'invoices_past_due' => 'Date limite de paiement dépassée', 'upcoming_invoices' => 'Factures à venir', 'average_invoice' => 'Moyenne de facturation', - + // list pages 'archive' => 'Archiver', 'delete' => 'Supprimer', @@ -276,7 +276,7 @@ return array( // Payment page 'secure_payment' => 'Paiement sécurisé', 'card_number' => 'Numéro de carte', - 'expiration_month' => 'Mois d\'expiration', + 'expiration_month' => 'Mois d\'expiration', 'expiration_year' => 'Année d\'expiration', 'cvv' => 'CVV', @@ -297,8 +297,8 @@ return array( 'remove_logo_link' => 'Cliquez ici', ], - 'logout' => 'Se déconnecter', - 'sign_up_to_save' => 'Connectez vous pour sauvegarder votre travail', + 'logout' => 'Se déconnecter', + 'sign_up_to_save' => 'Connectez vous pour sauvegarder votre travail', 'agree_to_terms' =>'J\'accepte les conditions d\'utilisation d\'Invoice ninja :terms', 'terms_of_service' => 'Conditions d\'utilisation', 'email_taken' => 'L\'adresse courriel existe déjà', @@ -319,7 +319,7 @@ return array( 'field_label' => 'Nom du champ', 'field_value' => 'Valeur du champ', 'edit' => 'Éditer', - 'view_as_recipient' => 'Voir en tant que destinataire', + 'view_as_recipient' => 'Voir en tant que destinataire', // product management 'product_library' => 'Inventaire', @@ -387,7 +387,7 @@ return array( 'notification_quote_sent_subject' => 'Le devis :invoice a été envoyé à :client', 'notification_quote_viewed_subject' => 'Le devis :invoice a été visionné par :client', 'notification_quote_sent' => 'Le devis :invoice de :amount a été envoyé au client :client.', - 'notification_quote_viewed' => 'Le devis :invoice de :amount a été visioné par le client :client.', + 'notification_quote_viewed' => 'Le devis :invoice de :amount a été visioné par le client :client.', 'session_expired' => 'Votre session a expiré.', @@ -426,7 +426,7 @@ return array( 'sample_data' => 'Données fictives présentées', 'hide' => 'Cacher', 'new_version_available' => 'Une nouvelle version de :releases_link est disponible. Vous utilisez v:user_version, la plus récente est v:latest_version', - + 'invoice_settings' => 'Paramètres des factures', 'invoice_number_prefix' => 'Préfixe du numéro de facture', @@ -436,7 +436,7 @@ return array( 'share_invoice_counter' => 'Partager le compteur de facture', 'invoice_issued_to' => 'Facture destinée à', 'invalid_counter' => 'Pour éviter un éventuel conflit, merci de définir un préfixe pour le numéro de facture ou pour le numéro de devis', - 'mark_sent' => 'Marquer comme envoyé', + 'mark_sent' => 'Marquer comme envoyé', 'gateway_help_1' => ':link to sign up for Authorize.net.', 'gateway_help_2' => ':link to sign up for Authorize.net.', @@ -452,7 +452,7 @@ return array( 'more_designs_self_host_text' => '', 'buy' => 'Acheter', 'bought_designs' => 'Les nouveaux modèles ont été ajoutés avec succès', - + 'sent' => 'envoyé', 'timesheets' => 'Feuilles de temps', @@ -460,7 +460,7 @@ return array( 'payment_cvv' => '*Numéro à 3 ou 4 chiffres au dos de votre carte', 'payment_footer1' => '*L\'adresse de facturation doit correspondre à celle enregistrée avec votre carte bancaire', 'payment_footer2' => '*Merci de cliquer sur "Payer maintenant" une seule fois. Le processus peut prendre jusqu\'à 1 minute.', - 'vat_number' => 'Numéro de TVA', + 'vat_number' => 'Numéro de TVA', 'id_number' => 'Numéro ID', 'white_label_link' => 'Marque blanche', @@ -485,7 +485,7 @@ return array( 'reason_for_canceling' => 'Aidez nous à améliorer notre site en nous disant pourquoi vous partez.', 'discount_percent' => 'Pourcent', 'discount_amount' => 'Montant', - + 'invoice_history' => 'Historique des factures', 'quote_history' => 'Historique des devis', 'current_version' => 'Version courante', @@ -503,7 +503,7 @@ return array( 'payment_email' => 'Email de paiement', 'quote_email' => 'Email de déclaration', 'reset_all' => 'Réinitialiser', - 'approve' => 'Accepter', + 'approve' => 'Accepter', 'token_billing_type_id' => 'Token Billing', 'token_billing_help' => 'Enables you to store credit cards with your gateway, and charge them at a later date.', @@ -527,7 +527,7 @@ return array( 'order_overview' => 'Order overview', 'match_address' => '*Address must match address associated with credit card.', 'click_once' => '*Please click "PAY NOW" only once - transaction may take up to 1 minute to process.', - + 'default_invoice_footer' => 'Définir par défaut', 'invoice_footer' => 'Pied de facture', 'save_as_default_footer' => 'Définir comme pied de facture par défatu', @@ -577,7 +577,7 @@ return array( 'notification_quote_approved' => 'The following client :client approved Quote :invoice for :amount.', 'resend_confirmation' => 'Resend confirmation email', 'confirmation_resent' => 'The confirmation email was resent', - + 'gateway_help_42' => ':link to sign up for BitPay.
Note: use a Legacy API Key, not an API token.', 'payment_type_credit_card' => 'Carte de crédit', 'payment_type_paypal' => 'PayPal', @@ -585,7 +585,7 @@ return array( 'knowledge_base' => 'Base de connaissances', 'partial' => 'Partiel', 'partial_remaining' => ':partial de :balance', - + 'more_fields' => 'Plus de champs', 'less_fields' => 'Moins de champs', 'client_name' => 'Nom du client', @@ -597,7 +597,7 @@ return array( 'view_documentation' => 'Voir documentation', 'app_title' => 'Free Open-Source Online Invoicing', 'app_description' => 'Invoice Ninja is a free, open-source solution for invoicing and billing customers. With Invoice Ninja, you can easily build and send beautiful invoices from any device that has access to the web. Your clients can print your invoices, download them as pdf files, and even pay you online from within the system.', - + 'rows' => 'lignes', 'www' => 'www', 'logo' => 'Logo', @@ -628,7 +628,7 @@ return array( 'archive_task' => 'Archiver tâche', 'restore_task' => 'Restaurer tâche', 'delete_task' => 'Supprimer tâche', - 'stop_task' => 'Arrêter tâcher', + 'stop_task' => 'Arrêter tâche', 'time' => 'Temps', 'start' => 'Début', 'stop' => 'Fin', @@ -682,7 +682,7 @@ return array( 'resume' => 'Resume', 'break_duration' => 'Break', - 'edit_details' => 'Editer détails', + 'edit_details' => 'Modifier', 'work' => 'Travail', 'timezone_unset' => 'Please :link to set your timezone', 'click_here' => 'cliquer ici', diff --git a/resources/lang/fr_CA/texts.php b/resources/lang/fr_CA/texts.php index 3e808ab19e7f..71b75ac7975a 100644 --- a/resources/lang/fr_CA/texts.php +++ b/resources/lang/fr_CA/texts.php @@ -1,4 +1,4 @@ - 'Facture #', 'po_number' => 'Numéro du bon de commande', 'po_number_short' => 'Bon de commande #', - 'frequency_id' => 'Fréquence', + 'frequency_id' => 'Fréquence', 'discount' => 'Remise', 'taxes' => 'Taxes', 'tax' => 'Taxe', - 'item' => 'Article', + 'item' => 'Article', 'description' => 'Description', 'unit_cost' => 'Coût unitaire', 'quantity' => 'Quantité', @@ -117,11 +117,11 @@ return array( 'billed_client' => 'client facturé', 'billed_clients' => 'clients facturés', 'active_client' => 'client actif', - 'active_clients' => 'clients actifs', + 'active_clients' => 'clients actifs', 'invoices_past_due' => 'Date limite de paiement dépassée', 'upcoming_invoices' => 'Factures à venir', 'average_invoice' => 'Moyenne de facturation', - + // list pages 'archive' => 'Archiver', 'delete' => 'Supprimer', @@ -276,7 +276,7 @@ return array( // Payment page 'secure_payment' => 'Paiement sécurisé', 'card_number' => 'Numéro de carte', - 'expiration_month' => 'Mois d\'expiration', + 'expiration_month' => 'Mois d\'expiration', 'expiration_year' => 'Année d\'expiration', 'cvv' => 'CVV', @@ -297,8 +297,8 @@ return array( 'remove_logo_link' => 'Cliquez ici', ], - 'logout' => 'Se déconnecter', - 'sign_up_to_save' => 'Connectez vous pour sauvegarder votre travail', + 'logout' => 'Se déconnecter', + 'sign_up_to_save' => 'Connectez vous pour sauvegarder votre travail', 'agree_to_terms' =>'J\'accepte les conditions d\'utilisation d\'Invoice ninja :terms', 'terms_of_service' => 'Conditions d\'utilisation', 'email_taken' => 'L\'adresse courriel existe déjà', @@ -319,7 +319,7 @@ return array( 'field_label' => 'Nom du champ', 'field_value' => 'Valeur du champ', 'edit' => 'Éditer', - 'view_as_recipient' => 'Voir en tant que destinataire', + 'view_as_recipient' => 'Voir en tant que destinataire', // product management 'product_library' => 'Inventaire', @@ -387,7 +387,7 @@ return array( 'notification_quote_sent_subject' => 'Le devis :invoice a été envoyé à :client', 'notification_quote_viewed_subject' => 'Le devis :invoice a été visionné par :client', 'notification_quote_sent' => 'Le devis :invoice de :amount a été envoyé au client :client.', - 'notification_quote_viewed' => 'Le devis :invoice de :amount a été visioné par le client :client.', + 'notification_quote_viewed' => 'Le devis :invoice de :amount a été visioné par le client :client.', 'session_expired' => 'Votre session a expiré.', @@ -426,7 +426,7 @@ return array( 'sample_data' => 'Données fictives présentées', 'hide' => 'Cacher', 'new_version_available' => 'Une nouvelle version de :releases_link est disponible. Vous utilisez v:user_version, la plus récente est v:latest_version', - + 'invoice_settings' => 'Paramètres des factures', 'invoice_number_prefix' => 'Préfixe du numéro de facture', @@ -436,7 +436,7 @@ return array( 'share_invoice_counter' => 'Partager le compteur de facture', 'invoice_issued_to' => 'Facture destinée à', 'invalid_counter' => 'Pour éviter un éventuel conflit, merci de définir un préfixe pour le numéro de facture ou pour le numéro de devis', - 'mark_sent' => 'Marquer comme envoyé', + 'mark_sent' => 'Marquer comme envoyé', 'gateway_help_1' => ':link to sign up for Authorize.net.', 'gateway_help_2' => ':link to sign up for Authorize.net.', @@ -452,7 +452,7 @@ return array( 'more_designs_self_host_text' => '', 'buy' => 'Acheter', 'bought_designs' => 'Les nouveaux modèles ont été ajoutés avec succès', - + 'sent' => 'envoyé', 'timesheets' => 'Feuilles de temps', @@ -460,7 +460,7 @@ return array( 'payment_cvv' => '*This is the 3-4 digit number onthe back of your card', 'payment_footer1' => '*Billing address must match address associated with credit card.', 'payment_footer2' => '*Please click "PAY NOW" only once - transaction may take up to 1 minute to process.', - 'vat_number' => 'Numéro de TVA', + 'vat_number' => 'Numéro de TVA', 'id_number' => 'Numéro ID', 'white_label_link' => 'Marque blanche', @@ -485,7 +485,7 @@ return array( 'reason_for_canceling' => 'Aidez nous à améliorer notre site en nous disant pourquoi vous partez.', 'discount_percent' => 'Pourcent', 'discount_amount' => 'Montant', - + 'invoice_history' => 'Historique des factures', 'quote_history' => 'Historique des devis', 'current_version' => 'Version courante', @@ -503,7 +503,7 @@ return array( 'payment_email' => 'Courriel de paiement', 'quote_email' => 'Courriel de devis', 'reset_all' => 'Tout remettre à zéro', - 'approve' => 'Approuver', + 'approve' => 'Approuver', 'token_billing_type_id' => 'Token Billing', 'token_billing_help' => 'Enables you to store credit cards with your gateway, and charge them at a later date.', @@ -527,7 +527,7 @@ return array( 'order_overview' => 'Order overview', 'match_address' => '*Address must match address associated with credit card.', 'click_once' => '*Please click "PAY NOW" only once - transaction may take up to 1 minute to process.', - + 'default_invoice_footer' => 'Set default invoice footer', 'invoice_footer' => 'Invoice footer', 'save_as_default_footer' => 'Save as default footer', @@ -571,13 +571,13 @@ return array( 'send_email' => 'Send email', 'set_password' => 'Set Password', 'converted' => 'Converted', - + 'email_approved' => 'Email me when a quote is approved', 'notification_quote_approved_subject' => 'Quote :invoice was approved by :client', 'notification_quote_approved' => 'The following client :client approved Quote :invoice for :amount.', 'resend_confirmation' => 'Resend confirmation email', 'confirmation_resent' => 'The confirmation email was resent', - + 'gateway_help_42' => ':link to sign up for BitPay.
Note: use a Legacy API Key, not an API token.', 'payment_type_credit_card' => 'Credit card', 'payment_type_paypal' => 'PayPal', @@ -597,7 +597,7 @@ return array( 'view_documentation' => 'View Documentation', 'app_title' => 'Free Open-Source Online Invoicing', 'app_description' => 'Invoice Ninja is a free, open-source solution for invoicing and billing customers. With Invoice Ninja, you can easily build and send beautiful invoices from any device that has access to the web. Your clients can print your invoices, download them as pdf files, and even pay you online from within the system.', - + 'rows' => 'rows', 'www' => 'www', 'logo' => 'Logo', @@ -619,50 +619,50 @@ return array( 'last_invoice_sent' => 'Last invoice sent :date', 'processed_updates' => 'Successfully completed update', - 'tasks' => 'Tasks', - 'new_task' => 'New Task', - 'start_time' => 'Start Time', - 'created_task' => 'Successfully created task', - 'updated_task' => 'Successfully updated task', + 'tasks' => 'Tâches', + 'new_task' => 'Nouvelle Tâche', + 'start_time' => 'Démarrée à', + 'created_task' => 'Tâche créée avec succès', + 'updated_task' => 'Tâche modifiée avec succès', 'edit_task' => 'Edit Task', - 'archive_task' => 'Archive Task', - 'restore_task' => 'Restore Task', - 'delete_task' => 'Delete Task', - 'stop_task' => 'Stop Task', + 'archive_task' => 'Archiver la Tâche', + 'restore_task' => 'Restaurer la Tâche', + 'delete_task' => 'Supprimer la Tâche', + 'stop_task' => 'Arrêter la Tâche', 'time' => 'Time', - 'start' => 'Start', - 'stop' => 'Stop', + 'start' => 'Démarrer', + 'stop' => 'Arrêter', 'now' => 'Now', 'timer' => 'Timer', 'manual' => 'Manual', 'date_and_time' => 'Date & Time', - 'second' => 'second', - 'seconds' => 'seconds', + 'second' => 'seconde', + 'seconds' => 'secondes', 'minute' => 'minute', 'minutes' => 'minutes', - 'hour' => 'hour', - 'hours' => 'hours', - 'task_details' => 'Task Details', - 'duration' => 'Duration', - 'end_time' => 'End Time', + 'hour' => 'heure', + 'hours' => 'heures', + 'task_details' => 'Détails de la Tâche', + 'duration' => 'Durée', + 'end_time' => 'Arrêtée à', 'end' => 'End', 'invoiced' => 'Invoiced', 'logged' => 'Logged', 'running' => 'Running', - 'task_error_multiple_clients' => 'The tasks can\'t belong to different clients', - 'task_error_running' => 'Please stop running tasks first', - 'task_error_invoiced' => 'Tasks have already been invoiced', - 'restored_task' => 'Successfully restored task', - 'archived_task' => 'Successfully archived task', - 'archived_tasks' => 'Successfully archived :count tasks', - 'deleted_task' => 'Successfully deleted task', - 'deleted_tasks' => 'Successfully deleted :count tasks', - 'create_task' => 'Create Task', - 'stopped_task' => 'Successfully stopped task', - 'invoice_task' => 'Invoice Task', + 'task_error_multiple_clients' => 'Une tâche ne peut appartenir à plusieurs clients', + 'task_error_running' => 'Merci d\'arrêter les tâches en cours', + 'task_error_invoiced' => 'Ces tâches ont déjà été facturées', + 'restored_task' => 'Tâche restaurée avec succès', + 'archived_task' => 'Tâche archivée avec succès', + 'archived_tasks' => ':count tâches archivées avec succès', + 'deleted_task' => 'Tâche supprimée avec succès', + 'deleted_tasks' => ':count tâches supprimées avec succès', + 'create_task' => 'Créer une Tâche', + 'stopped_task' => 'Tâche arrêtée avec succès', + 'invoice_task' => 'Facturer Tâche', 'invoice_labels' => 'Invoice Labels', - 'prefix' => 'Prefix', - 'counter' => 'Counter', + 'prefix' => 'Préfixe', + 'counter' => 'Compteur', 'payment_type_dwolla' => 'Dwolla', 'gateway_help_43' => ':link to sign up for Dwolla.', @@ -681,12 +681,12 @@ return array( 'pro_plan_feature7' => 'Customize Invoice Field Titles & Numbering', 'pro_plan_feature8' => 'Option to Attach PDFs to Client Emails', - 'resume' => 'Resume', - 'break_duration' => 'Break', - 'edit_details' => 'Edit Details', - 'work' => 'Work', + 'resume' => 'Continuer', + 'break_duration' => 'Pause', + 'edit_details' => 'Modifier', + 'work' => 'Travail', 'timezone_unset' => 'Please :link to set your timezone', - 'click_here' => 'click here', + 'click_here' => 'cliquer içi', 'email_receipt' => 'Email payment receipt to the client', 'created_payment_emailed_client' => 'Successfully created payment and emailed client', From b9c00a0531ad355ca98a95b7928ec9bb9b402990 Mon Sep 17 00:00:00 2001 From: Hillel Coren Date: Sun, 12 Jul 2015 22:43:45 +0300 Subject: [PATCH 04/58] Re-worked editing task details --- app/Http/Controllers/AccountController.php | 3 + .../Controllers/AccountGatewayController.php | 4 +- app/Http/Controllers/InvoiceController.php | 7 +- app/Http/Controllers/PaymentController.php | 77 ++-- app/Http/Controllers/TaskController.php | 58 +-- app/Http/routes.php | 1 + app/Models/Account.php | 11 +- app/Models/Invoice.php | 7 +- app/Models/Task.php | 62 ++- app/Ninja/Mailers/Mailer.php | 12 +- app/Ninja/Repositories/InvoiceRepository.php | 12 + app/Ninja/Repositories/TaskRepository.php | 24 +- .../2015_07_08_114333_simplify_tasks.php | 73 ++++ public/css/built.css | 2 + public/css/style.css | 2 + resources/lang/da/texts.php | 18 + resources/lang/de/texts.php | 19 + resources/lang/en/texts.php | 23 +- resources/lang/es/texts.php | 19 + resources/lang/es_ES/texts.php | 19 + resources/lang/fr/texts.php | 19 + resources/lang/fr_CA/texts.php | 19 + resources/lang/it/texts.php | 19 + resources/lang/lt/texts.php | 19 + resources/lang/nb_NO/texts.php | 19 + resources/lang/nl/texts.php | 19 + resources/lang/pt_BR/texts.php | 19 + resources/lang/sv/texts.php | 19 + .../views/accounts/account_gateway.blade.php | 32 +- resources/views/accounts/details.blade.php | 7 + .../views/accounts/invoice_settings.blade.php | 6 +- resources/views/header.blade.php | 30 +- resources/views/invoices/edit.blade.php | 37 +- resources/views/payments/payment.blade.php | 2 + resources/views/tasks/edit.blade.php | 374 ++++++++++-------- 35 files changed, 804 insertions(+), 289 deletions(-) create mode 100644 database/migrations/2015_07_08_114333_simplify_tasks.php diff --git a/app/Http/Controllers/AccountController.php b/app/Http/Controllers/AccountController.php index 540567d9b339..dcb9438c1a8c 100644 --- a/app/Http/Controllers/AccountController.php +++ b/app/Http/Controllers/AccountController.php @@ -647,6 +647,9 @@ class AccountController extends BaseController $user->username = trim(Input::get('email')); $user->email = trim(strtolower(Input::get('email'))); $user->phone = trim(Input::get('phone')); + if (Utils::isNinja()) { + $user->dark_mode = Input::get('dark_mode') ? true : false; + } $user->save(); } diff --git a/app/Http/Controllers/AccountGatewayController.php b/app/Http/Controllers/AccountGatewayController.php index b6f3c5df22d5..ff4c84c649be 100644 --- a/app/Http/Controllers/AccountGatewayController.php +++ b/app/Http/Controllers/AccountGatewayController.php @@ -257,6 +257,8 @@ class AccountGatewayController extends BaseController } $accountGateway->accepted_credit_cards = $cardCount; + $accountGateway->show_address = Input::get('show_address') ? true : false; + $accountGateway->update_address = Input::get('update_address') ? true : false; $accountGateway->config = json_encode($config); if ($accountGatewayPublicId) { @@ -278,7 +280,7 @@ class AccountGatewayController extends BaseController Session::flash('message', $message); - return Redirect::to('company/payments'); + return Redirect::to("gateways/{$accountGateway->public_id}/edit"); } } diff --git a/app/Http/Controllers/InvoiceController.php b/app/Http/Controllers/InvoiceController.php index 0a9220c7271d..20c938e8252f 100644 --- a/app/Http/Controllers/InvoiceController.php +++ b/app/Http/Controllers/InvoiceController.php @@ -375,10 +375,9 @@ class InvoiceController extends BaseController 'method' => 'POST', 'url' => 'invoices', 'title' => trans('texts.new_invoice'), - 'client' => $client, - 'tasks' => Session::get('tasks') ? json_encode(Session::get('tasks')) : null); + 'client' => $client); $data = array_merge($data, self::getViewModel()); - + return View::make('invoices.edit', $data); } @@ -417,7 +416,7 @@ class InvoiceController extends BaseController ), 'recurringHelp' => $recurringHelp, 'invoiceLabels' => Auth::user()->account->getInvoiceLabels(), - + 'tasks' => Session::get('tasks') ? json_encode(Session::get('tasks')) : null, ]; } diff --git a/app/Http/Controllers/PaymentController.php b/app/Http/Controllers/PaymentController.php index a68841d580dd..6248a8e6917b 100644 --- a/app/Http/Controllers/PaymentController.php +++ b/app/Http/Controllers/PaymentController.php @@ -233,33 +233,41 @@ class PaymentController extends BaseController private function convertInputForOmnipay($input) { - $country = Country::find($input['country_id']); - - return [ + $data = [ 'firstName' => $input['first_name'], 'lastName' => $input['last_name'], 'number' => $input['card_number'], 'expiryMonth' => $input['expiration_month'], 'expiryYear' => $input['expiration_year'], 'cvv' => $input['cvv'], - 'billingAddress1' => $input['address1'], - 'billingAddress2' => $input['address2'], - 'billingCity' => $input['city'], - 'billingState' => $input['state'], - 'billingPostcode' => $input['postal_code'], - 'billingCountry' => $country->iso_3166_2, - 'shippingAddress1' => $input['address1'], - 'shippingAddress2' => $input['address2'], - 'shippingCity' => $input['city'], - 'shippingState' => $input['state'], - 'shippingPostcode' => $input['postal_code'], - 'shippingCountry' => $country->iso_3166_2 ]; + + if (isset($input['country_id'])) { + $country = Country::find($input['country_id']); + + $data = array_merge($data, [ + 'billingAddress1' => $input['address1'], + 'billingAddress2' => $input['address2'], + 'billingCity' => $input['city'], + 'billingState' => $input['state'], + 'billingPostcode' => $input['postal_code'], + 'billingCountry' => $country->iso_3166_2, + 'shippingAddress1' => $input['address1'], + 'shippingAddress2' => $input['address2'], + 'shippingCity' => $input['city'], + 'shippingState' => $input['state'], + 'shippingPostcode' => $input['postal_code'], + 'shippingCountry' => $country->iso_3166_2 + ]); + } + + return $data; } private function getPaymentDetails($invitation, $input = null) { $invoice = $invitation->invoice; + $account = $invoice->account; $key = $invoice->account_id.'-'.$invoice->invoice_number; $currencyCode = $invoice->client->currency ? $invoice->client->currency->code : ($invoice->account->currency ? $invoice->account->currency->code : 'USD'); @@ -330,6 +338,7 @@ class PaymentController extends BaseController 'currencyId' => $client->getCurrencyId(), 'account' => $client->account, 'hideLogo' => $account->isWhiteLabel(), + 'showAddress' => $accountGateway->show_address, ]; return View::make('payments.payment', $data); @@ -498,19 +507,30 @@ class PaymentController extends BaseController public function do_payment($invitationKey, $onSite = true, $useToken = false) { - $rules = array( + $invitation = Invitation::with('invoice.invoice_items', 'invoice.client.currency', 'invoice.client.account.currency', 'invoice.client.account.account_gateways.gateway')->where('invitation_key', '=', $invitationKey)->firstOrFail(); + $invoice = $invitation->invoice; + $client = $invoice->client; + $account = $client->account; + $accountGateway = $account->getGatewayByType(Session::get('payment_type')); + + $rules = [ 'first_name' => 'required', 'last_name' => 'required', 'card_number' => 'required', 'expiration_month' => 'required', 'expiration_year' => 'required', 'cvv' => 'required', - 'address1' => 'required', - 'city' => 'required', - 'state' => 'required', - 'postal_code' => 'required', - 'country_id' => 'required', - ); + ]; + + if ($accountGateway->show_address) { + $rules = array_merge($rules, [ + 'address1' => 'required', + 'city' => 'required', + 'state' => 'required', + 'postal_code' => 'required', + 'country_id' => 'required', + ]); + } if ($onSite) { $validator = Validator::make(Input::all(), $rules); @@ -522,23 +542,16 @@ class PaymentController extends BaseController ->withInput(); } } - - $invitation = Invitation::with('invoice.invoice_items', 'invoice.client.currency', 'invoice.client.account.currency', 'invoice.client.account.account_gateways.gateway')->where('invitation_key', '=', $invitationKey)->firstOrFail(); - $invoice = $invitation->invoice; - $client = $invoice->client; - $account = $client->account; - $accountGateway = $account->getGatewayByType(Session::get('payment_type')); - - /* - if ($onSite) { + + if ($onSite && $accountGateway->update_address) { $client->address1 = trim(Input::get('address1')); $client->address2 = trim(Input::get('address2')); $client->city = trim(Input::get('city')); $client->state = trim(Input::get('state')); $client->postal_code = trim(Input::get('postal_code')); + $client->country_id = Input::get('country_id'); $client->save(); } - */ try { $gateway = self::createGateway($accountGateway); diff --git a/app/Http/Controllers/TaskController.php b/app/Http/Controllers/TaskController.php index a1b12dad293c..9ca05f64f5d4 100644 --- a/app/Http/Controllers/TaskController.php +++ b/app/Http/Controllers/TaskController.php @@ -13,31 +13,19 @@ use DropdownButton; use App\Models\Client; use App\Models\Task; -/* -use Auth; -use Cache; - -use App\Models\Activity; -use App\Models\Contact; -use App\Models\Invoice; -use App\Models\Size; -use App\Models\PaymentTerm; -use App\Models\Industry; -use App\Models\Currency; -use App\Models\Country; -*/ - use App\Ninja\Repositories\TaskRepository; +use App\Ninja\Repositories\InvoiceRepository; class TaskController extends BaseController { protected $taskRepo; - public function __construct(TaskRepository $taskRepo) + public function __construct(TaskRepository $taskRepo, InvoiceRepository $invoiceRepo) { parent::__construct(); $this->taskRepo = $taskRepo; + $this->invoiceRepo = $invoiceRepo; } /** @@ -71,8 +59,8 @@ class TaskController extends BaseController ->addColumn('client_name', function ($model) { return $model->client_public_id ? link_to('clients/'.$model->client_public_id, Utils::getClientDisplayName($model)) : ''; }); } - return $table->addColumn('start_time', function($model) { return Utils::fromSqlDateTime($model->start_time); }) - ->addColumn('duration', function($model) { return gmdate('H:i:s', $model->is_running ? time() - strtotime($model->start_time) : $model->duration); }) + return $table->addColumn('created_at', function($model) { return Task::calcStartTime($model); }) + ->addColumn('time_log', function($model) { return gmdate('H:i:s', Task::calcDuration($model)); }) ->addColumn('description', function($model) { return $model->description; }) ->addColumn('invoice_number', function($model) { return self::getStatusLabel($model); }) ->addColumn('dropdown', function ($model) { @@ -169,8 +157,16 @@ class TaskController extends BaseController if ($task->invoice) { $actions[] = ['url' => URL::to("inovices/{$task->invoice->public_id}/edit"), 'label' => trans("texts.view_invoice")]; } else { - $actions[] = ['url' => 'javascript:submitAction("invoice")', 'label' => trans("texts.invoice_task")]; + $actions[] = ['url' => 'javascript:submitAction("invoice")', 'label' => trans("texts.create_invoice")]; + + // check for any open invoices + $invoices = $task->client_id ? $this->invoiceRepo->findOpenInvoices($task->client_id) : []; + + foreach ($invoices as $invoice) { + $actions[] = ['url' => 'javascript:submitAction("add_to_invoice", '.$invoice->public_id.')', 'label' => trans("texts.add_to_invoice", ["invoice" => $invoice->invoice_number])]; + } } + $actions[] = DropdownButton::DIVIDER; if (!$task->trashed()) { $actions[] = ['url' => 'javascript:submitAction("archive")', 'label' => trans('texts.archive_task')]; @@ -178,15 +174,15 @@ class TaskController extends BaseController } else { $actions[] = ['url' => 'javascript:submitAction("restore")', 'label' => trans('texts.restore_task')]; } - + $data = [ 'task' => $task, 'clientPublicId' => $task->client ? $task->client->public_id : 0, 'method' => 'PUT', 'url' => 'tasks/'.$publicId, 'title' => trans('texts.edit_task'), - 'duration' => $task->resume_time ? ($task->duration + strtotime('now') - strtotime($task->resume_time)) : (strtotime('now') - strtotime($task->start_time)), - 'actions' => $actions + 'duration' => $task->is_running ? $task->getCurrentDuration() : $task->getDuration(), + 'actions' => $actions, ]; $data = array_merge($data, self::getViewModel()); @@ -216,7 +212,7 @@ class TaskController extends BaseController { $action = Input::get('action'); - if (in_array($action, ['archive', 'delete', 'invoice', 'restore'])) { + if (in_array($action, ['archive', 'delete', 'invoice', 'restore', 'add_to_invoice'])) { return self::bulk(); } @@ -235,12 +231,11 @@ class TaskController extends BaseController $this->taskRepo->save($ids, ['action' => $action]); Session::flash('message', trans('texts.stopped_task')); return Redirect::to('tasks'); - } else if ($action == 'invoice') { - + } else if ($action == 'invoice' || $action == 'add_to_invoice') { $tasks = Task::scope($ids)->with('client')->get(); $clientPublicId = false; $data = []; - + foreach ($tasks as $task) { if ($task->client) { if (!$clientPublicId) { @@ -258,16 +253,21 @@ class TaskController extends BaseController Session::flash('error', trans('texts.task_error_invoiced')); return Redirect::to('tasks'); } - + $data[] = [ 'publicId' => $task->public_id, 'description' => $task->description, - 'startTime' => Utils::fromSqlDateTime($task->start_time), - 'duration' => round($task->duration / (60 * 60), 2) + 'startTime' => $task->getStartTime(), + 'duration' => $task->getHours(), ]; } - return Redirect::to("invoices/create/{$clientPublicId}")->with('tasks', $data); + if ($action == 'invoice') { + return Redirect::to("invoices/create/{$clientPublicId}")->with('tasks', $data); + } else { + $invoiceId = Input::get('invoice_id'); + return Redirect::to("invoices/{$invoiceId}/edit")->with('tasks', $data); + } } else { $count = $this->taskRepo->bulk($ids, $action); diff --git a/app/Http/routes.php b/app/Http/routes.php index 0825afb383e4..542c2638e7e8 100644 --- a/app/Http/routes.php +++ b/app/Http/routes.php @@ -1,5 +1,6 @@ share_counter ? $this->quote_number_counter : $this->invoice_number_counter; $prefix .= $isQuote ? $this->quote_number_prefix : $this->invoice_number_prefix; - + // confirm the invoice number isn't already taken do { $number = $prefix.str_pad($counter, 4, "0", STR_PAD_LEFT); @@ -186,11 +186,14 @@ class Account extends Eloquent { // check if the user modified the invoice number if (!$isRecurring && $invoiceNumber != $this->getNextInvoiceNumber($isQuote)) { - $number = intval(preg_replace('/[^0-9]/', '', $invoiceNumber)); + // remove the prefix + $prefix = $isQuote ? $this->quote_number_prefix : $this->invoice_number_prefix; + $invoiceNumber = preg_replace('/^'.$prefix.'/', '', $invoiceNumber); + $invoiceNumber = intval(preg_replace('/[^0-9]/', '', $invoiceNumber)); if ($isQuote && !$this->share_counter) { - $this->quote_number_counter = $number + 1; + $this->quote_number_counter = $invoiceNumber + 1; } else { - $this->invoice_number_counter = $number + 1; + $this->invoice_number_counter = $invoiceNumber + 1; } // otherwise, just increment the counter } else { diff --git a/app/Models/Invoice.php b/app/Models/Invoice.php index 6207bfb14041..27c0999c7a2c 100644 --- a/app/Models/Invoice.php +++ b/app/Models/Invoice.php @@ -252,8 +252,11 @@ class Invoice extends EntityModel } } -Invoice::created(function ($invoice) { +Invoice::creating(function ($invoice) { $invoice->account->incrementCounter($invoice->invoice_number, $invoice->is_quote, $invoice->recurring_invoice_id); +}); + +Invoice::created(function ($invoice) { Activity::createInvoice($invoice); }); @@ -267,4 +270,4 @@ Invoice::deleting(function ($invoice) { Invoice::restoring(function ($invoice) { Activity::restoreInvoice($invoice); -}); +}); \ No newline at end of file diff --git a/app/Models/Task.php b/app/Models/Task.php index 68cfaffe2e75..4ccbf9688ab3 100644 --- a/app/Models/Task.php +++ b/app/Models/Task.php @@ -1,7 +1,7 @@ belongsTo('App\Models\Client')->withTrashed(); } + + public static function calcStartTime($task) + { + $parts = json_decode($task->time_log) ?: []; + + if (count($parts)) { + return Utils::timestampToDateTimeString($parts[0][0]); + } else { + return ''; + } + } + + public function getStartTime() + { + return self::calcStartTime($this); + } + + public static function calcDuration($task) + { + $duration = 0; + $parts = json_decode($task->time_log) ?: []; + + foreach ($parts as $part) { + if (count($part) == 1 || !$part[1]) { + $duration += time() - $part[0]; + } else { + $duration += $part[1] - $part[0]; + } + } + + return $duration; + } + + public function getDuration() + { + return self::calcDuration($this); + } + + public function getCurrentDuration() + { + $parts = json_decode($this->time_log) ?: []; + $part = $parts[count($parts)-1]; + + if (count($part) == 1 || !$part[1]) { + return time() - $part[0]; + } else { + return 0; + } + } + + public function hasPreviousDuration() + { + $parts = json_decode($this->time_log) ?: []; + return count($parts) && (count($parts[0]) && $parts[0][1]); + } + + public function getHours() + { + return round($this->getDuration() / (60 * 60), 2); + } } Task::created(function ($task) { diff --git a/app/Ninja/Mailers/Mailer.php b/app/Ninja/Mailers/Mailer.php index 47c7756ab59f..ffd0abdadee8 100644 --- a/app/Ninja/Mailers/Mailer.php +++ b/app/Ninja/Mailers/Mailer.php @@ -34,10 +34,14 @@ class Mailer }); return true; - } catch (Exception $e) { - $response = $e->getResponse()->getBody()->getContents(); - $response = json_decode($response); - return nl2br($response->Message); + } catch (Exception $exception) { + if (method_exists($exception, 'getResponse')) { + $response = $exception->getResponse()->getBody()->getContents(); + $response = json_decode($response); + return nl2br($response->Message); + } else { + return $exception->getMessage(); + } } } } diff --git a/app/Ninja/Repositories/InvoiceRepository.php b/app/Ninja/Repositories/InvoiceRepository.php index f4caa63ee2e2..ce0397d64b4d 100644 --- a/app/Ninja/Repositories/InvoiceRepository.php +++ b/app/Ninja/Repositories/InvoiceRepository.php @@ -536,4 +536,16 @@ class InvoiceRepository return count($invoices); } + + public function findOpenInvoices($clientId) + { + return Invoice::scope() + ->whereClientId($clientId) + ->whereIsQuote(false) + ->whereIsRecurring(false) + ->whereHasTasks(true) + ->where('balance', '>', 0) + ->select(['public_id', 'invoice_number']) + ->get(); + } } diff --git a/app/Ninja/Repositories/TaskRepository.php b/app/Ninja/Repositories/TaskRepository.php index feb764850ad3..4504e78fb7fa 100644 --- a/app/Ninja/Repositories/TaskRepository.php +++ b/app/Ninja/Repositories/TaskRepository.php @@ -23,7 +23,7 @@ class TaskRepository }) ->where('contacts.deleted_at', '=', null) ->where('clients.deleted_at', '=', null) - ->select('tasks.public_id', 'clients.name as client_name', 'clients.public_id as client_public_id', 'contacts.first_name', 'contacts.email', 'contacts.last_name', 'invoices.invoice_status_id', 'tasks.start_time', 'tasks.description', 'tasks.duration', 'tasks.is_deleted', 'tasks.deleted_at', 'invoices.invoice_number', 'invoices.public_id as invoice_public_id', 'tasks.is_running'); + ->select('tasks.public_id', 'clients.name as client_name', 'clients.public_id as client_public_id', 'contacts.first_name', 'contacts.email', 'contacts.last_name', 'invoices.invoice_status_id', 'tasks.description', 'tasks.is_deleted', 'tasks.deleted_at', 'invoices.invoice_number', 'invoices.public_id as invoice_public_id', 'tasks.is_running', 'tasks.time_log', 'tasks.created_at'); if ($clientPublicId) { $query->where('clients.public_id', '=', $clientPublicId); @@ -60,36 +60,20 @@ class TaskRepository $task->description = trim($data['description']); } - $timeLog = $task->time_log ? json_decode($task->time_log, true) : []; - + //$timeLog = $task->time_log ? json_decode($task->time_log, true) : []; + $timeLog = isset($data['time_log']) ? json_decode($data['time_log']) : []; if ($data['action'] == 'start') { - $task->start_time = Carbon::now()->toDateTimeString(); $task->is_running = true; $timeLog[] = [strtotime('now'), false]; } else if ($data['action'] == 'resume') { - $task->break_duration = strtotime('now') - strtotime($task->start_time) + $task->duration; - $task->resume_time = Carbon::now()->toDateTimeString(); $task->is_running = true; $timeLog[] = [strtotime('now'), false]; } else if ($data['action'] == 'stop' && $task->is_running) { - if ($task->resume_time) { - $task->duration = $task->duration + strtotime('now') - strtotime($task->resume_time); - $task->resume_time = null; - } else { - $task->duration = strtotime('now') - strtotime($task->start_time); - } - $timeLog[count($timeLog)-1][1] = strtotime('now'); + $timeLog[count($timeLog)-1][1] = time(); $task->is_running = false; - } else if ($data['action'] == 'save' && !$task->is_running) { - $task->start_time = $data['start_time']; - $task->duration = $data['duration']; - $task->break_duration = $data['break_duration']; } - $task->duration = max($task->duration, 0); - $task->break_duration = max($task->break_duration, 0); $task->time_log = json_encode($timeLog); - $task->save(); return $task; diff --git a/database/migrations/2015_07_08_114333_simplify_tasks.php b/database/migrations/2015_07_08_114333_simplify_tasks.php new file mode 100644 index 000000000000..b0136a33ec91 --- /dev/null +++ b/database/migrations/2015_07_08_114333_simplify_tasks.php @@ -0,0 +1,73 @@ +start_time); + if (!$task->time_log || !count(json_decode($task->time_log))) { + $task->time_log = json_encode([[$startTime, $startTime + $task->duration]]); + $task->save(); + } elseif ($task->getDuration() != intval($task->duration)) { + $task->time_log = json_encode([[$startTime, $startTime + $task->duration]]); + $task->save(); + } + } + + Schema::table('tasks', function($table) + { + $table->dropColumn('start_time'); + $table->dropColumn('duration'); + $table->dropColumn('break_duration'); + $table->dropColumn('resume_time'); + }); + + Schema::table('users', function($table) + { + $table->boolean('dark_mode')->default(false)->nullable(); + }); + + Schema::table('users', function($table) + { + $table->dropColumn('theme_id'); + }); + + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('tasks', function($table) + { + $table->timestamp('start_time')->nullable(); + $table->integer('duration')->nullable(); + $table->timestamp('resume_time')->nullable(); + $table->integer('break_duration')->nullable(); + }); + + Schema::table('users', function($table) + { + $table->dropColumn('dark_mode'); + }); + Schema::table('users', function($table) + { + $table->integer('theme_id')->nullable(); + }); + } + +} diff --git a/public/css/built.css b/public/css/built.css index 5c4e52f5c523..ab4839c61fd8 100644 --- a/public/css/built.css +++ b/public/css/built.css @@ -2433,6 +2433,8 @@ th {border-left: 1px solid #d26b26; } .table>thead>tr>th, .table>tbody>tr>th, .table>tfoot>tr>th, .table>thead>tr>td, .table>tbody>tr>td, .table>tfoot>tr>td { vertical-align: middle; border-top: none; +} +table.invoice-table>thead>tr>th, table.invoice-table>tbody>tr>th, table.invoice-table>tfoot>tr>th, table.invoice-table>thead>tr>td, table.invoice-table>tbody>tr>td, table.invoice-table>tfoot>tr>td { border-bottom: 1px solid #dfe0e1; } table.dataTable.no-footer { diff --git a/public/css/style.css b/public/css/style.css index 5e536810750b..6c31f3041907 100644 --- a/public/css/style.css +++ b/public/css/style.css @@ -83,6 +83,8 @@ th {border-left: 1px solid #d26b26; } .table>thead>tr>th, .table>tbody>tr>th, .table>tfoot>tr>th, .table>thead>tr>td, .table>tbody>tr>td, .table>tfoot>tr>td { vertical-align: middle; border-top: none; +} +table.invoice-table>thead>tr>th, table.invoice-table>tbody>tr>th, table.invoice-table>tfoot>tr>th, table.invoice-table>thead>tr>td, table.invoice-table>tbody>tr>td, table.invoice-table>tfoot>tr>td { border-bottom: 1px solid #dfe0e1; } table.dataTable.no-footer { diff --git a/resources/lang/da/texts.php b/resources/lang/da/texts.php index 706250b733d1..5c9b160aa6bb 100644 --- a/resources/lang/da/texts.php +++ b/resources/lang/da/texts.php @@ -706,6 +706,24 @@ return array( 'login' => 'Login', 'or' => 'or', + 'email_error' => 'There was a problem sending the email', + 'created_by_recurring' => 'Created by recurring invoice :invoice', + 'confirm_recurring_timing' => 'Note: emails are sent at the start of the hour.', + 'old_browser' => 'Please use a newer browser', + 'payment_terms_help' => 'Sets the default invoice due date', + 'unlink_account' => 'Unlink Account', + 'unlink' => 'Unlink', + 'show_address' => 'Show Address', + 'show_address_help' => 'Require client to provide their billing address', + 'update_address' => 'Update Address', + 'update_address_help' => 'Update client\'s address with provided details', + 'times' => 'Times', + 'set_now' => 'Set now', + 'dark_mode' => 'Dark Mode', + 'dark_mode_help' => 'Show white text on black background', + 'add_to_invoice' => 'Add to invoice :invoice', + 'create_new_invoice' => 'Create new invoice', + 'task_errors' => 'Please correct any overlapping times', diff --git a/resources/lang/de/texts.php b/resources/lang/de/texts.php index 461b87811485..482c29ef0b1c 100644 --- a/resources/lang/de/texts.php +++ b/resources/lang/de/texts.php @@ -697,5 +697,24 @@ return array( 'login' => 'Login', 'or' => 'oder', + 'email_error' => 'There was a problem sending the email', + 'created_by_recurring' => 'Created by recurring invoice :invoice', + 'confirm_recurring_timing' => 'Note: emails are sent at the start of the hour.', + 'old_browser' => 'Please use a newer browser', + 'payment_terms_help' => 'Sets the default invoice due date', + 'unlink_account' => 'Unlink Account', + 'unlink' => 'Unlink', + 'show_address' => 'Show Address', + 'show_address_help' => 'Require client to provide their billing address', + 'update_address' => 'Update Address', + 'update_address_help' => 'Update client\'s address with provided details', + 'times' => 'Times', + 'set_now' => 'Set now', + 'dark_mode' => 'Dark Mode', + 'dark_mode_help' => 'Show white text on black background', + 'add_to_invoice' => 'Add to invoice :invoice', + 'create_new_invoice' => 'Create new invoice', + 'task_errors' => 'Please correct any overlapping times', + ); \ No newline at end of file diff --git a/resources/lang/en/texts.php b/resources/lang/en/texts.php index 728fd8c37690..7861fb9a80ac 100644 --- a/resources/lang/en/texts.php +++ b/resources/lang/en/texts.php @@ -276,9 +276,9 @@ return array( // Payment page 'secure_payment' => 'Secure Payment', - 'card_number' => 'Card number', - 'expiration_month' => 'Expiration month', - 'expiration_year' => 'Expiration year', + 'card_number' => 'Card Number', + 'expiration_month' => 'Expiration Month', + 'expiration_year' => 'Expiration Year', 'cvv' => 'CVV', // Security alerts @@ -526,11 +526,11 @@ return array( 'token_billing_secure' => 'The data is stored securely by :stripe_link', 'support' => 'Support', - 'contact_information' => 'Contact information', + 'contact_information' => 'Contact Information', '256_encryption' => '256-Bit Encryption', 'amount_due' => 'Amount due', - 'billing_address' => 'Billing address', - 'billing_method' => 'Billing method', + 'billing_address' => 'Billing Address', + 'billing_method' => 'Billing Method', 'order_overview' => 'Order overview', 'match_address' => '*Address must match address associated with credit card.', 'click_once' => '*Please click "PAY NOW" only once - transaction may take up to 1 minute to process.', @@ -711,5 +711,16 @@ return array( 'payment_terms_help' => 'Sets the default invoice due date', 'unlink_account' => 'Unlink Account', 'unlink' => 'Unlink', + 'show_address' => 'Show Address', + 'show_address_help' => 'Require client to provide their billing address', + 'update_address' => 'Update Address', + 'update_address_help' => 'Update client\'s address with provided details', + 'times' => 'Times', + 'set_now' => 'Set now', + 'dark_mode' => 'Dark Mode', + 'dark_mode_help' => 'Show white text on black background', + 'add_to_invoice' => 'Add to invoice :invoice', + 'create_new_invoice' => 'Create new invoice', + 'task_errors' => 'Please correct any overlapping times', ); diff --git a/resources/lang/es/texts.php b/resources/lang/es/texts.php index 0d32d825eed3..826902066b98 100644 --- a/resources/lang/es/texts.php +++ b/resources/lang/es/texts.php @@ -676,5 +676,24 @@ return array( 'login' => 'Login', 'or' => 'or', + 'email_error' => 'There was a problem sending the email', + 'created_by_recurring' => 'Created by recurring invoice :invoice', + 'confirm_recurring_timing' => 'Note: emails are sent at the start of the hour.', + 'old_browser' => 'Please use a newer browser', + 'payment_terms_help' => 'Sets the default invoice due date', + 'unlink_account' => 'Unlink Account', + 'unlink' => 'Unlink', + 'show_address' => 'Show Address', + 'show_address_help' => 'Require client to provide their billing address', + 'update_address' => 'Update Address', + 'update_address_help' => 'Update client\'s address with provided details', + 'times' => 'Times', + 'set_now' => 'Set now', + 'dark_mode' => 'Dark Mode', + 'dark_mode_help' => 'Show white text on black background', + 'add_to_invoice' => 'Add to invoice :invoice', + 'create_new_invoice' => 'Create new invoice', + 'task_errors' => 'Please correct any overlapping times', + ); \ No newline at end of file diff --git a/resources/lang/es_ES/texts.php b/resources/lang/es_ES/texts.php index 38e48e8276d7..e230e930f1ec 100644 --- a/resources/lang/es_ES/texts.php +++ b/resources/lang/es_ES/texts.php @@ -705,6 +705,25 @@ return array( 'login' => 'Login', 'or' => 'or', + 'email_error' => 'There was a problem sending the email', + 'created_by_recurring' => 'Created by recurring invoice :invoice', + 'confirm_recurring_timing' => 'Note: emails are sent at the start of the hour.', + 'old_browser' => 'Please use a newer browser', + 'payment_terms_help' => 'Sets the default invoice due date', + 'unlink_account' => 'Unlink Account', + 'unlink' => 'Unlink', + 'show_address' => 'Show Address', + 'show_address_help' => 'Require client to provide their billing address', + 'update_address' => 'Update Address', + 'update_address_help' => 'Update client\'s address with provided details', + 'times' => 'Times', + 'set_now' => 'Set now', + 'dark_mode' => 'Dark Mode', + 'dark_mode_help' => 'Show white text on black background', + 'add_to_invoice' => 'Add to invoice :invoice', + 'create_new_invoice' => 'Create new invoice', + 'task_errors' => 'Please correct any overlapping times', + ); \ No newline at end of file diff --git a/resources/lang/fr/texts.php b/resources/lang/fr/texts.php index 010c5557709c..e16f140f5eb3 100644 --- a/resources/lang/fr/texts.php +++ b/resources/lang/fr/texts.php @@ -697,6 +697,25 @@ return array( 'login' => 'Connexion', 'or' => 'ou', + 'email_error' => 'There was a problem sending the email', + 'created_by_recurring' => 'Created by recurring invoice :invoice', + 'confirm_recurring_timing' => 'Note: emails are sent at the start of the hour.', + 'old_browser' => 'Please use a newer browser', + 'payment_terms_help' => 'Sets the default invoice due date', + 'unlink_account' => 'Unlink Account', + 'unlink' => 'Unlink', + 'show_address' => 'Show Address', + 'show_address_help' => 'Require client to provide their billing address', + 'update_address' => 'Update Address', + 'update_address_help' => 'Update client\'s address with provided details', + 'times' => 'Times', + 'set_now' => 'Set now', + 'dark_mode' => 'Dark Mode', + 'dark_mode_help' => 'Show white text on black background', + 'add_to_invoice' => 'Add to invoice :invoice', + 'create_new_invoice' => 'Create new invoice', + 'task_errors' => 'Please correct any overlapping times', + ); diff --git a/resources/lang/fr_CA/texts.php b/resources/lang/fr_CA/texts.php index 3e808ab19e7f..724cf87a4321 100644 --- a/resources/lang/fr_CA/texts.php +++ b/resources/lang/fr_CA/texts.php @@ -698,5 +698,24 @@ return array( 'login' => 'Login', 'or' => 'or', + 'email_error' => 'There was a problem sending the email', + 'created_by_recurring' => 'Created by recurring invoice :invoice', + 'confirm_recurring_timing' => 'Note: emails are sent at the start of the hour.', + 'old_browser' => 'Please use a newer browser', + 'payment_terms_help' => 'Sets the default invoice due date', + 'unlink_account' => 'Unlink Account', + 'unlink' => 'Unlink', + 'show_address' => 'Show Address', + 'show_address_help' => 'Require client to provide their billing address', + 'update_address' => 'Update Address', + 'update_address_help' => 'Update client\'s address with provided details', + 'times' => 'Times', + 'set_now' => 'Set now', + 'dark_mode' => 'Dark Mode', + 'dark_mode_help' => 'Show white text on black background', + 'add_to_invoice' => 'Add to invoice :invoice', + 'create_new_invoice' => 'Create new invoice', + 'task_errors' => 'Please correct any overlapping times', + ); diff --git a/resources/lang/it/texts.php b/resources/lang/it/texts.php index 8b5a3e5047de..4892d732c3f4 100644 --- a/resources/lang/it/texts.php +++ b/resources/lang/it/texts.php @@ -700,6 +700,25 @@ return array( 'login' => 'Login', 'or' => 'or', + 'email_error' => 'There was a problem sending the email', + 'created_by_recurring' => 'Created by recurring invoice :invoice', + 'confirm_recurring_timing' => 'Note: emails are sent at the start of the hour.', + 'old_browser' => 'Please use a newer browser', + 'payment_terms_help' => 'Sets the default invoice due date', + 'unlink_account' => 'Unlink Account', + 'unlink' => 'Unlink', + 'show_address' => 'Show Address', + 'show_address_help' => 'Require client to provide their billing address', + 'update_address' => 'Update Address', + 'update_address_help' => 'Update client\'s address with provided details', + 'times' => 'Times', + 'set_now' => 'Set now', + 'dark_mode' => 'Dark Mode', + 'dark_mode_help' => 'Show white text on black background', + 'add_to_invoice' => 'Add to invoice :invoice', + 'create_new_invoice' => 'Create new invoice', + 'task_errors' => 'Please correct any overlapping times', + ); diff --git a/resources/lang/lt/texts.php b/resources/lang/lt/texts.php index 66f56de588f8..eaf8bbb9e5d7 100644 --- a/resources/lang/lt/texts.php +++ b/resources/lang/lt/texts.php @@ -707,6 +707,25 @@ return array( 'login' => 'Login', 'or' => 'or', + 'email_error' => 'There was a problem sending the email', + 'created_by_recurring' => 'Created by recurring invoice :invoice', + 'confirm_recurring_timing' => 'Note: emails are sent at the start of the hour.', + 'old_browser' => 'Please use a newer browser', + 'payment_terms_help' => 'Sets the default invoice due date', + 'unlink_account' => 'Unlink Account', + 'unlink' => 'Unlink', + 'show_address' => 'Show Address', + 'show_address_help' => 'Require client to provide their billing address', + 'update_address' => 'Update Address', + 'update_address_help' => 'Update client\'s address with provided details', + 'times' => 'Times', + 'set_now' => 'Set now', + 'dark_mode' => 'Dark Mode', + 'dark_mode_help' => 'Show white text on black background', + 'add_to_invoice' => 'Add to invoice :invoice', + 'create_new_invoice' => 'Create new invoice', + 'task_errors' => 'Please correct any overlapping times', + ); diff --git a/resources/lang/nb_NO/texts.php b/resources/lang/nb_NO/texts.php index a5d9d569da21..1e2a21df14e2 100644 --- a/resources/lang/nb_NO/texts.php +++ b/resources/lang/nb_NO/texts.php @@ -705,6 +705,25 @@ return array( 'login' => 'Login', 'or' => 'or', + 'email_error' => 'There was a problem sending the email', + 'created_by_recurring' => 'Created by recurring invoice :invoice', + 'confirm_recurring_timing' => 'Note: emails are sent at the start of the hour.', + 'old_browser' => 'Please use a newer browser', + 'payment_terms_help' => 'Sets the default invoice due date', + 'unlink_account' => 'Unlink Account', + 'unlink' => 'Unlink', + 'show_address' => 'Show Address', + 'show_address_help' => 'Require client to provide their billing address', + 'update_address' => 'Update Address', + 'update_address_help' => 'Update client\'s address with provided details', + 'times' => 'Times', + 'set_now' => 'Set now', + 'dark_mode' => 'Dark Mode', + 'dark_mode_help' => 'Show white text on black background', + 'add_to_invoice' => 'Add to invoice :invoice', + 'create_new_invoice' => 'Create new invoice', + 'task_errors' => 'Please correct any overlapping times', + ); \ No newline at end of file diff --git a/resources/lang/nl/texts.php b/resources/lang/nl/texts.php index 6dad49264bfe..f4e64362a2aa 100644 --- a/resources/lang/nl/texts.php +++ b/resources/lang/nl/texts.php @@ -700,6 +700,25 @@ return array( 'login' => 'Login', 'or' => 'or', + 'email_error' => 'There was a problem sending the email', + 'created_by_recurring' => 'Created by recurring invoice :invoice', + 'confirm_recurring_timing' => 'Note: emails are sent at the start of the hour.', + 'old_browser' => 'Please use a newer browser', + 'payment_terms_help' => 'Sets the default invoice due date', + 'unlink_account' => 'Unlink Account', + 'unlink' => 'Unlink', + 'show_address' => 'Show Address', + 'show_address_help' => 'Require client to provide their billing address', + 'update_address' => 'Update Address', + 'update_address_help' => 'Update client\'s address with provided details', + 'times' => 'Times', + 'set_now' => 'Set now', + 'dark_mode' => 'Dark Mode', + 'dark_mode_help' => 'Show white text on black background', + 'add_to_invoice' => 'Add to invoice :invoice', + 'create_new_invoice' => 'Create new invoice', + 'task_errors' => 'Please correct any overlapping times', + ); diff --git a/resources/lang/pt_BR/texts.php b/resources/lang/pt_BR/texts.php index be2080b68341..bfa9c57fa910 100644 --- a/resources/lang/pt_BR/texts.php +++ b/resources/lang/pt_BR/texts.php @@ -700,5 +700,24 @@ return array( 'login' => 'Login', 'or' => 'or', + 'email_error' => 'There was a problem sending the email', + 'created_by_recurring' => 'Created by recurring invoice :invoice', + 'confirm_recurring_timing' => 'Note: emails are sent at the start of the hour.', + 'old_browser' => 'Please use a newer browser', + 'payment_terms_help' => 'Sets the default invoice due date', + 'unlink_account' => 'Unlink Account', + 'unlink' => 'Unlink', + 'show_address' => 'Show Address', + 'show_address_help' => 'Require client to provide their billing address', + 'update_address' => 'Update Address', + 'update_address_help' => 'Update client\'s address with provided details', + 'times' => 'Times', + 'set_now' => 'Set now', + 'dark_mode' => 'Dark Mode', + 'dark_mode_help' => 'Show white text on black background', + 'add_to_invoice' => 'Add to invoice :invoice', + 'create_new_invoice' => 'Create new invoice', + 'task_errors' => 'Please correct any overlapping times', + ); diff --git a/resources/lang/sv/texts.php b/resources/lang/sv/texts.php index 86a9de4b8471..e26f1ad515dc 100644 --- a/resources/lang/sv/texts.php +++ b/resources/lang/sv/texts.php @@ -703,6 +703,25 @@ return array( 'login' => 'Login', 'or' => 'or', + 'email_error' => 'There was a problem sending the email', + 'created_by_recurring' => 'Created by recurring invoice :invoice', + 'confirm_recurring_timing' => 'Note: emails are sent at the start of the hour.', + 'old_browser' => 'Please use a newer browser', + 'payment_terms_help' => 'Sets the default invoice due date', + 'unlink_account' => 'Unlink Account', + 'unlink' => 'Unlink', + 'show_address' => 'Show Address', + 'show_address_help' => 'Require client to provide their billing address', + 'update_address' => 'Update Address', + 'update_address_help' => 'Update client\'s address with provided details', + 'times' => 'Times', + 'set_now' => 'Set now', + 'dark_mode' => 'Dark Mode', + 'dark_mode_help' => 'Show white text on black background', + 'add_to_invoice' => 'Add to invoice :invoice', + 'create_new_invoice' => 'Create new invoice', + 'task_errors' => 'Please correct any overlapping times', + ); diff --git a/resources/views/accounts/account_gateway.blade.php b/resources/views/accounts/account_gateway.blade.php index 13d6cd337e27..2aa79c2dbb68 100644 --- a/resources/views/accounts/account_gateway.blade.php +++ b/resources/views/accounts/account_gateway.blade.php @@ -14,9 +14,12 @@
@if ($accountGateway) - {!! Former::populateField('payment_type_id', $paymentTypeId) !!} {!! Former::populateField('gateway_id', $accountGateway->gateway_id) !!} - {!! Former::populateField('recommendedGateway_id', $accountGateway->gateway_id) !!} + {!! Former::populateField('payment_type_id', $paymentTypeId) !!} + {!! Former::populateField('recommendedGateway_id', $accountGateway->gateway_id) !!} + {!! Former::populateField('show_address', intval($accountGateway->show_address)) !!} + {!! Former::populateField('update_address', intval($accountGateway->update_address)) !!} + @if ($config) @foreach ($accountGateway->fields as $field => $junk) @if (in_array($field, $hiddenFields)) @@ -28,6 +31,8 @@ @endif @else {!! Former::populateField('gateway_id', GATEWAY_STRIPE) !!} + {!! Former::populateField('show_address', 1) !!} + {!! Former::populateField('update_address', 1) !!} @endif {!! Former::select('payment_type_id') @@ -77,6 +82,15 @@ @endforeach + {!! Former::checkbox('show_address') + ->label(trans('texts.billing_address')) + ->text(trans('texts.show_address_help')) + ->addGroupClass('gateway-option') !!} + {!! Former::checkbox('update_address') + ->label(' ') + ->text(trans('texts.update_address_help')) + ->addGroupClass('gateway-option') !!} + {!! Former::checkboxes('creditCardTypes[]') ->label('Accepted Credit Cards') ->checkboxes($creditCardTypes) @@ -131,11 +145,25 @@ } } + function enableUpdateAddress(event) { + var disabled = !$('#show_address').is(':checked'); + $('#update_address').prop('disabled', disabled); + $('label[for=update_address]').css('color', disabled ? '#888' : '#000'); + if (disabled) { + $('#update_address').prop('checked', false); + } else if (event) { + $('#update_address').prop('checked', true); + } + } + $(function() { setPaymentType(); @if ($accountGateway) $('.payment-type-option').hide(); @endif + + $('#show_address').change(enableUpdateAddress); + enableUpdateAddress(); }) diff --git a/resources/views/accounts/details.blade.php b/resources/views/accounts/details.blade.php index feef5eceb57e..90475d384b75 100644 --- a/resources/views/accounts/details.blade.php +++ b/resources/views/accounts/details.blade.php @@ -22,6 +22,9 @@ {{ Former::populateField('last_name', $account->users()->first()->last_name) }} {{ Former::populateField('email', $account->users()->first()->email) }} {{ Former::populateField('phone', $account->users()->first()->phone) }} + @if (Utils::isNinja()) + {{ Former::populateField('dark_mode', intval($account->users()->first()->dark_mode)) }} + @endif @endif
@@ -88,6 +91,10 @@ {!! Former::text('last_name') !!} {!! Former::text('email') !!} {!! Former::text('phone') !!} + @if (Utils::isNinja()) + {!! Former::checkbox('dark_mode')->text(trans('texts.dark_mode_help')) !!} + @endif + @if (Auth::user()->confirmed) {!! Former::actions( Button::primary(trans('texts.change_password'))->small()->withAttributes(['onclick'=>'showChangePassword()'])) !!} @elseif (Auth::user()->registered) diff --git a/resources/views/accounts/invoice_settings.blade.php b/resources/views/accounts/invoice_settings.blade.php index b46bdfd17b0c..b3b03011578c 100644 --- a/resources/views/accounts/invoice_settings.blade.php +++ b/resources/views/accounts/invoice_settings.blade.php @@ -23,8 +23,7 @@ {{ Former::populateField('custom_invoice_taxes2', intval($account->custom_invoice_taxes2)) }} {{ Former::populateField('share_counter', intval($account->share_counter)) }} {{ Former::populateField('pdf_email_attachment', intval($account->pdf_email_attachment)) }} - {{ Former::populateField('utf8_invoices', intval($account->utf8_invoices)) }} - {{ Former::populateField('auto_wrap', intval($account->auto_wrap)) }} + {{ Former::populateField('utf8_invoices', intval($account->utf8_invoices)) }}
@@ -99,9 +98,6 @@
{!! Former::checkbox('pdf_email_attachment')->text(trans('texts.enable')) !!} {!! Former::checkbox('utf8_invoices')->text(trans('texts.enable')) !!} -
- {!! Former::checkbox('auto_wrap')->text(trans('texts.enable')) !!} -
diff --git a/resources/views/header.blade.php b/resources/views/header.blade.php index f4fc371e66ce..857cbb6b0664 100644 --- a/resources/views/header.blade.php +++ b/resources/views/header.blade.php @@ -25,6 +25,23 @@ } } + @if (Auth::check() && Auth::user()->dark_mode) + body { + background: #000 !important; + color: white !important; + } + + .panel-body { + background: #272822 !important; + /*background: #e6e6e6 !important;*/ + } + + .panel-default { + border-color: #444; + } + @endif + + @include('script') @@ -309,6 +326,15 @@ showSignUp(); @endif + $('ul.navbar-settings, ul.navbar-history').hover(function () { + //$('.user-accounts').find('li').hide(); + //$('.user-accounts').css({display: 'none'}); + //console.log($('.user-accounts').dropdown('')) + if ($('.user-accounts').css('display') == 'block') { + $('.user-accounts').dropdown('toggle'); + } + }); + @yield('onReady') }); @@ -409,7 +435,7 @@
-
-

 

- {!! Former::actions( - Former::select('invoice_design_id')->style('display:inline;width:120px')->fromQuery($invoiceDesigns, 'name', 'id')->onchange('onSelectChange()')->raw(), - Button::success(trans('texts.save'))->withAttributes(['onclick' => 'submitForm()'])->large()->appendIcon(Icon::create('floppy-disk')) - ) !!} +
+ {!! Former::select('invoice_design_id')->style('display:inline;width:120px')->fromQuery($invoiceDesigns, 'name', 'id')->onchange('onSelectChange()')->raw() !!} +
+ {!! Button::normal(trans('texts.documentation'))->asLinkTo(PDFMAKE_DOCS)->withAttributes(['target' => '_blank'])->appendIcon(Icon::create('info-sign')) !!} + {!! Button::normal(trans('texts.cancel'))->asLinkTo(URL::to('/company/advanced_settings/invoice_design'))->appendIcon(Icon::create('remove-circle')) !!} + {!! Button::success(trans('texts.save'))->withAttributes(['onclick' => 'submitForm()'])->appendIcon(Icon::create('floppy-disk')) !!} +
+
@if (!Auth::user()->isPro()) + +@stop \ No newline at end of file From 5249e24fa26c9f1c1ca583dd6c2a1f167b52bbc6 Mon Sep 17 00:00:00 2001 From: Hillel Coren Date: Mon, 3 Aug 2015 10:26:31 +0300 Subject: [PATCH 20/58] Git push --- app/Http/routes.php | 1 + 1 file changed, 1 insertion(+) diff --git a/app/Http/routes.php b/app/Http/routes.php index e016e3841c09..dc58f5d14eb1 100644 --- a/app/Http/routes.php +++ b/app/Http/routes.php @@ -2,6 +2,7 @@ //dd("We're currently undergoing a brief maintenance, we'll be right back."); + /* |-------------------------------------------------------------------------- | Application Routes From 29e90cae0b29616663cbd9d5492759cd5b4c3d83 Mon Sep 17 00:00:00 2001 From: Hillel Coren Date: Mon, 3 Aug 2015 11:02:35 +0300 Subject: [PATCH 21/58] Minor fix --- app/Http/Middleware/StartupCheck.php | 2 +- app/Http/routes.php | 3 --- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/app/Http/Middleware/StartupCheck.php b/app/Http/Middleware/StartupCheck.php index a6c2741977c8..a0b7fd2b1d09 100644 --- a/app/Http/Middleware/StartupCheck.php +++ b/app/Http/Middleware/StartupCheck.php @@ -158,7 +158,7 @@ class StartupCheck } } - if (preg_match('/(?i)msie [2-8]/', $_SERVER['HTTP_USER_AGENT'])) { + if (isset($_SERVER['HTTP_USER_AGENT']) && preg_match('/(?i)msie [2-8]/', $_SERVER['HTTP_USER_AGENT'])) { Session::flash('error', trans('texts.old_browser')); } diff --git a/app/Http/routes.php b/app/Http/routes.php index dc58f5d14eb1..a9c322632db0 100644 --- a/app/Http/routes.php +++ b/app/Http/routes.php @@ -1,8 +1,5 @@ Date: Mon, 3 Aug 2015 11:52:47 +0300 Subject: [PATCH 22/58] Disabled datepicker localization --- app/Http/Controllers/PaymentController.php | 1 + resources/views/master.blade.php | 5 ++++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/app/Http/Controllers/PaymentController.php b/app/Http/Controllers/PaymentController.php index 6632ce843b3b..712f19dce6c5 100644 --- a/app/Http/Controllers/PaymentController.php +++ b/app/Http/Controllers/PaymentController.php @@ -389,6 +389,7 @@ class PaymentController extends BaseController 'currencyId' => 1, 'paymentTitle' => $affiliate->payment_title, 'paymentSubtitle' => $affiliate->payment_subtitle, + 'showAddress' => true, ]; return View::make('payments.payment', $data); diff --git a/resources/views/master.blade.php b/resources/views/master.blade.php index 59a486405da7..b9dec31654c2 100644 --- a/resources/views/master.blade.php +++ b/resources/views/master.blade.php @@ -53,10 +53,13 @@ 'sSearch': '' } } ); - + + /* $.extend( true, $.fn.datepicker.defaults, { language:'{{App::getLocale()}}' }); + */ + From 4b7d14363038ea62b7144b24909753e38b570515 Mon Sep 17 00:00:00 2001 From: Hillel Coren Date: Mon, 3 Aug 2015 22:08:07 +0300 Subject: [PATCH 23/58] Minor fixes --- app/Http/Controllers/Auth/AuthController.php | 2 +- app/Http/Controllers/UserController.php | 6 +----- app/Libraries/Utils.php | 6 ++++++ app/Models/Account.php | 2 +- app/Ninja/Repositories/AccountRepository.php | 6 +++++- public/js/built.js | 2 +- public/js/script.js | 2 +- resources/views/accounts/details.blade.php | 2 +- resources/views/header.blade.php | 6 +++--- resources/views/invoices/edit.blade.php | 2 +- resources/views/user_account.blade.php | 2 +- 11 files changed, 22 insertions(+), 16 deletions(-) diff --git a/app/Http/Controllers/Auth/AuthController.php b/app/Http/Controllers/Auth/AuthController.php index e17135fe7146..a5897ac6879d 100644 --- a/app/Http/Controllers/Auth/AuthController.php +++ b/app/Http/Controllers/Auth/AuthController.php @@ -62,7 +62,7 @@ class AuthController extends Controller { $userId = Auth::check() ? Auth::user()->id : null; $user = User::where('email', '=', $request->input('email'))->first(); - if ($user->failed_logins >= 3) { + if ($user && $user->failed_logins >= 3) { Session::flash('error', 'These credentials do not match our records.'); return redirect()->to('login'); } diff --git a/app/Http/Controllers/UserController.php b/app/Http/Controllers/UserController.php index 50b66b69f720..85b4cede7d9a 100644 --- a/app/Http/Controllers/UserController.php +++ b/app/Http/Controllers/UserController.php @@ -382,10 +382,6 @@ class UserController extends BaseController public function manageCompanies() { - $data = [ - - ]; - - return View::make('users.account_management', $data); + return View::make('users.account_management'); } } diff --git a/app/Libraries/Utils.php b/app/Libraries/Utils.php index b38911371476..1efcf4b229a8 100644 --- a/app/Libraries/Utils.php +++ b/app/Libraries/Utils.php @@ -3,6 +3,7 @@ use Auth; use Cache; use DB; +use App; use Schema; use Session; use Request; @@ -69,6 +70,11 @@ class Utils return Auth::check() && Auth::user()->isPro(); } + public static function isEnglish() + { + return App::getLocale() == 'en'; + } + public static function getUserType() { if (Utils::isNinja()) { diff --git a/app/Models/Account.php b/app/Models/Account.php index be307f6ca775..e8cde5293c09 100644 --- a/app/Models/Account.php +++ b/app/Models/Account.php @@ -147,7 +147,7 @@ class Account extends Eloquent public function getLogoPath() { $fileName = 'logo/' . $this->account_key; - return file_exists($fileName.'.png') ? $fileName.'.png' : $fileName.'.jpg'; + return file_exists($fileName.'.png') && $this->utf8_invoices ? $fileName.'.png' : $fileName.'.jpg'; } public function getLogoWidth() diff --git a/app/Ninja/Repositories/AccountRepository.php b/app/Ninja/Repositories/AccountRepository.php index 98ef973f674f..222463c4b532 100644 --- a/app/Ninja/Repositories/AccountRepository.php +++ b/app/Ninja/Repositories/AccountRepository.php @@ -6,7 +6,7 @@ use Session; use Utils; use DB; use stdClass; - +use Schema; use App\Models\AccountGateway; use App\Models\Invitation; use App\Models\Invoice; @@ -250,6 +250,10 @@ class AccountRepository public function findUserAccounts($userId1, $userId2 = false) { + if (!Schema::hasTable('user_accounts')) { + return false; + } + $query = UserAccount::where('user_id1', '=', $userId1) ->orWhere('user_id2', '=', $userId1) ->orWhere('user_id3', '=', $userId1) diff --git a/public/js/built.js b/public/js/built.js index 0a22d2a5a35e..a47d137523b7 100644 --- a/public/js/built.js +++ b/public/js/built.js @@ -29884,7 +29884,7 @@ function generatePDF(invoice, javascript, force, cb) { if (!invoice || !javascript) { return; } - console.log('== generatePDF - force: %s', force); + //console.log('== generatePDF - force: %s', force); if (force || !invoiceOld) { refreshTimer = null; } else { diff --git a/public/js/script.js b/public/js/script.js index dded462d101a..eabb1be9f671 100644 --- a/public/js/script.js +++ b/public/js/script.js @@ -13,7 +13,7 @@ function generatePDF(invoice, javascript, force, cb) { if (!invoice || !javascript) { return; } - console.log('== generatePDF - force: %s', force); + //console.log('== generatePDF - force: %s', force); if (force || !invoiceOld) { refreshTimer = null; } else { diff --git a/resources/views/accounts/details.blade.php b/resources/views/accounts/details.blade.php index 89a2a179f94b..b433f55b7353 100644 --- a/resources/views/accounts/details.blade.php +++ b/resources/views/accounts/details.blade.php @@ -51,7 +51,7 @@ @if (file_exists($account->getLogoPath()))
- {!! HTML::image($account->getLogoPath().'?no_cache='.time(), "Logo") !!}   + {!! HTML::image($account->getLogoPath().'?no_cache='.time(), 'Logo', ['width' => 200]) !!}   {{ trans('texts.remove_logo') }}

@endif diff --git a/resources/views/header.blade.php b/resources/views/header.blade.php index e42e71f27574..9abb87690796 100644 --- a/resources/views/header.blade.php +++ b/resources/views/header.blade.php @@ -253,12 +253,12 @@ }, 2000); $('#search').blur(function(){ - $('#search').css('width', '150px'); + $('#search').css('width', '{{ Utils::isEnglish() ? 150 : 100 }}px'); $('ul.navbar-right').show(); }); $('#search').focus(function(){ - $('#search').css('width', '256px'); + $('#search').css('width', '{{ Utils::isEnglish() ? 256 : 206 }}px'); $('ul.navbar-right').hide(); if (!window.hasOwnProperty('searchData')) { $.get('{{ URL::route('getSearchData') }}', function(data) { @@ -461,7 +461,7 @@ diff --git a/resources/views/invoices/edit.blade.php b/resources/views/invoices/edit.blade.php index 317b72965392..db574f26b340 100644 --- a/resources/views/invoices/edit.blade.php +++ b/resources/views/invoices/edit.blade.php @@ -94,7 +94,7 @@ {!! Former::text('end_date')->data_bind("datePicker: end_date, valueUpdate: 'afterkeydown'") ->data_date_format(Session::get(SESSION_DATE_PICKER_FORMAT, DEFAULT_DATE_PICKER_FORMAT))->append('') !!} - @if ($invoice && $invoice->recurring_invoice_id) + @if ($invoice && $invoice->recurring_invoice)
{!! trans('texts.created_by_recurring', ['invoice' => link_to('/invoices/'.$invoice->recurring_invoice->public_id, $invoice->recurring_invoice->invoice_number)]) !!}
diff --git a/resources/views/user_account.blade.php b/resources/views/user_account.blade.php index 7364f33f6afc..9384f621b498 100644 --- a/resources/views/user_account.blade.php +++ b/resources/views/user_account.blade.php @@ -1,5 +1,5 @@
  • - @if (isset($user_id)) + @if (isset($user_id) && $user_id != Auth::user()->id) @else From 8f80ccf4d792db071f76274ce306f3d401ae5533 Mon Sep 17 00:00:00 2001 From: Hillel Coren Date: Tue, 4 Aug 2015 14:38:48 +0300 Subject: [PATCH 24/58] Minor fixes --- app/Http/Controllers/AppController.php | 2 +- app/Ninja/Repositories/AccountRepository.php | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/app/Http/Controllers/AppController.php b/app/Http/Controllers/AppController.php index b135c045053e..bc6c699e728b 100644 --- a/app/Http/Controllers/AppController.php +++ b/app/Http/Controllers/AppController.php @@ -176,7 +176,7 @@ class AppController extends BaseController public function update() { - if (!Utils::isNinja() && Auth::check()) { + if (!Utils::isNinja()) { try { Artisan::call('migrate', array('--force' => true)); Artisan::call('db:seed', array('--force' => true, '--class' => 'PaymentLibrariesSeeder')); diff --git a/app/Ninja/Repositories/AccountRepository.php b/app/Ninja/Repositories/AccountRepository.php index 222463c4b532..5aaa6e8d4d90 100644 --- a/app/Ninja/Repositories/AccountRepository.php +++ b/app/Ninja/Repositories/AccountRepository.php @@ -316,6 +316,9 @@ class AccountRepository } public function syncUserAccounts($users, $proPlanPaid = false) { + if (!$users) { + return; + } if (!$proPlanPaid) { foreach ($users as $user) { From 2cfcdd1e777ebb8472759f5ef10b8a512e2e5653 Mon Sep 17 00:00:00 2001 From: Hillel Coren Date: Tue, 4 Aug 2015 17:33:30 +0300 Subject: [PATCH 25/58] Minor improvements --- app/Http/Controllers/HomeController.php | 4 ++-- resources/lang/da/texts.php | 2 +- resources/lang/de/texts.php | 2 +- resources/lang/en/texts.php | 3 ++- resources/lang/es/texts.php | 2 +- resources/lang/es_ES/texts.php | 2 +- resources/lang/fr/texts.php | 2 +- resources/lang/fr_CA/texts.php | 2 +- resources/lang/it/texts.php | 2 +- resources/lang/lt/texts.php | 2 +- resources/lang/nb_NO/texts.php | 2 +- resources/lang/nl/texts.php | 2 +- resources/lang/pt_BR/texts.php | 2 +- resources/lang/sv/texts.php | 2 +- resources/views/dashboard.blade.php | 6 +++--- resources/views/list.blade.php | 7 +++++-- 16 files changed, 24 insertions(+), 20 deletions(-) diff --git a/app/Http/Controllers/HomeController.php b/app/Http/Controllers/HomeController.php index 2645b0cbd98a..0f8226f077b1 100644 --- a/app/Http/Controllers/HomeController.php +++ b/app/Http/Controllers/HomeController.php @@ -72,9 +72,9 @@ class HomeController extends BaseController $user->news_feed_id = $newsFeedId; $user->save(); } - - Session::forget('news_feed_message'); } + + Session::forget('news_feed_message'); return 'success'; } diff --git a/resources/lang/da/texts.php b/resources/lang/da/texts.php index 580e366e7298..ced550498886 100644 --- a/resources/lang/da/texts.php +++ b/resources/lang/da/texts.php @@ -743,7 +743,7 @@ return array( 'recent_payments' => 'Recent Payments', 'outstanding' => 'Outstanding', 'manage_companies' => 'Manage Companies', - + 'total_revenue' => 'Total Revenue', diff --git a/resources/lang/de/texts.php b/resources/lang/de/texts.php index 7519119b40d6..9cd8866c9276 100644 --- a/resources/lang/de/texts.php +++ b/resources/lang/de/texts.php @@ -733,7 +733,7 @@ return array( 'invoice_no' => 'Rechnung Nr.', 'recent_payments' => 'Kürzliche Zahlungen', 'manage_companies' => 'Manage Companies', - + 'total_revenue' => 'Total Revenue', ); \ No newline at end of file diff --git a/resources/lang/en/texts.php b/resources/lang/en/texts.php index b9807c4c93b4..23b684fb2577 100644 --- a/resources/lang/en/texts.php +++ b/resources/lang/en/texts.php @@ -120,7 +120,7 @@ return array( 'active_clients' => 'active clients', 'invoices_past_due' => 'Invoices Past Due', 'upcoming_invoices' => 'Upcoming Invoices', - 'average_invoice' => 'Average invoice', + 'average_invoice' => 'Average Invoice', // list pages 'archive' => 'Archive', @@ -741,6 +741,7 @@ return array( 'recent_payments' => 'Recent Payments', 'outstanding' => 'Outstanding', 'manage_companies' => 'Manage Companies', + 'total_revenue' => 'Total Revenue', ); diff --git a/resources/lang/es/texts.php b/resources/lang/es/texts.php index 92ca314723b6..cf290277618c 100644 --- a/resources/lang/es/texts.php +++ b/resources/lang/es/texts.php @@ -713,7 +713,7 @@ return array( 'recent_payments' => 'Recent Payments', 'outstanding' => 'Outstanding', 'manage_companies' => 'Manage Companies', - + 'total_revenue' => 'Total Revenue', ); \ No newline at end of file diff --git a/resources/lang/es_ES/texts.php b/resources/lang/es_ES/texts.php index 97b333fbb2c2..8d6fd83a7f9a 100644 --- a/resources/lang/es_ES/texts.php +++ b/resources/lang/es_ES/texts.php @@ -742,7 +742,7 @@ return array( 'recent_payments' => 'Recent Payments', 'outstanding' => 'Outstanding', 'manage_companies' => 'Manage Companies', - + 'total_revenue' => 'Total Revenue', diff --git a/resources/lang/fr/texts.php b/resources/lang/fr/texts.php index 6fd60e17c4ba..6a87a6e78896 100644 --- a/resources/lang/fr/texts.php +++ b/resources/lang/fr/texts.php @@ -734,7 +734,7 @@ return array( 'recent_payments' => 'Recent Payments', 'outstanding' => 'Outstanding', 'manage_companies' => 'Manage Companies', - + 'total_revenue' => 'Total Revenue', diff --git a/resources/lang/fr_CA/texts.php b/resources/lang/fr_CA/texts.php index 0c0bf2e3a4a2..05d56c57821c 100644 --- a/resources/lang/fr_CA/texts.php +++ b/resources/lang/fr_CA/texts.php @@ -735,7 +735,7 @@ return array( 'recent_payments' => 'Recent Payments', 'outstanding' => 'Outstanding', 'manage_companies' => 'Manage Companies', - + 'total_revenue' => 'Total Revenue', ); diff --git a/resources/lang/it/texts.php b/resources/lang/it/texts.php index 9672b9ea533d..061bd060be8e 100644 --- a/resources/lang/it/texts.php +++ b/resources/lang/it/texts.php @@ -737,7 +737,7 @@ return array( 'recent_payments' => 'Recent Payments', 'outstanding' => 'Outstanding', 'manage_companies' => 'Manage Companies', - + 'total_revenue' => 'Total Revenue', diff --git a/resources/lang/lt/texts.php b/resources/lang/lt/texts.php index 15ca60fcba36..ba4f8715e5a1 100644 --- a/resources/lang/lt/texts.php +++ b/resources/lang/lt/texts.php @@ -744,7 +744,7 @@ return array( 'recent_payments' => 'Recent Payments', 'outstanding' => 'Outstanding', 'manage_companies' => 'Manage Companies', - + 'total_revenue' => 'Total Revenue', diff --git a/resources/lang/nb_NO/texts.php b/resources/lang/nb_NO/texts.php index c014c917637c..eeb80190ad5a 100644 --- a/resources/lang/nb_NO/texts.php +++ b/resources/lang/nb_NO/texts.php @@ -742,7 +742,7 @@ return array( 'recent_payments' => 'Recent Payments', 'outstanding' => 'Outstanding', 'manage_companies' => 'Manage Companies', - + 'total_revenue' => 'Total Revenue', diff --git a/resources/lang/nl/texts.php b/resources/lang/nl/texts.php index f82175f36ad9..aa8458c590ee 100644 --- a/resources/lang/nl/texts.php +++ b/resources/lang/nl/texts.php @@ -737,7 +737,7 @@ return array( 'recent_payments' => 'Recent Payments', 'outstanding' => 'Outstanding', 'manage_companies' => 'Manage Companies', - + 'total_revenue' => 'Total Revenue', diff --git a/resources/lang/pt_BR/texts.php b/resources/lang/pt_BR/texts.php index 875691412797..8bb24e732859 100644 --- a/resources/lang/pt_BR/texts.php +++ b/resources/lang/pt_BR/texts.php @@ -737,7 +737,7 @@ return array( 'recent_payments' => 'Recent Payments', 'outstanding' => 'Outstanding', 'manage_companies' => 'Manage Companies', - + 'total_revenue' => 'Total Revenue', ); diff --git a/resources/lang/sv/texts.php b/resources/lang/sv/texts.php index 13e443f81bdc..09aaa7998718 100644 --- a/resources/lang/sv/texts.php +++ b/resources/lang/sv/texts.php @@ -740,7 +740,7 @@ return array( 'recent_payments' => 'Recent Payments', 'outstanding' => 'Outstanding', 'manage_companies' => 'Manage Companies', - + 'total_revenue' => 'Total Revenue', diff --git a/resources/views/dashboard.blade.php b/resources/views/dashboard.blade.php index 864e7aeb1f89..f4e52f16e67f 100644 --- a/resources/views/dashboard.blade.php +++ b/resources/views/dashboard.blade.php @@ -7,6 +7,9 @@
    +
    + {{ trans('texts.total_revenue') }} +
    @if (count($paidToDate)) @foreach ($paidToDate as $item) @@ -16,9 +19,6 @@ {{ Utils::formatMoney(0) }} @endif
    -
    - {{ trans('texts.in_total_revenue') }} -
    diff --git a/resources/views/list.blade.php b/resources/views/list.blade.php index cc9d3e35ce99..915c176f8c06 100644 --- a/resources/views/list.blade.php +++ b/resources/views/list.blade.php @@ -24,13 +24,16 @@
    - + @if (Auth::user()->isPro() && $entityType == ENTITY_INVOICE) {!! Button::normal(trans('texts.quotes'))->asLinkTo(URL::to('/quotes'))->appendIcon(Icon::create('list')) !!} @elseif ($entityType == ENTITY_CLIENT) {!! Button::normal(trans('texts.credits'))->asLinkTo(URL::to('/credits'))->appendIcon(Icon::create('list')) !!} @endif - {!! Button::primary(trans("texts.new_$entityType"))->asLinkTo(URL::to("/{$entityType}s/create"))->appendIcon(Icon::create('plus-sign')) !!} + + @if ($entityType != ENTITY_TASK || Auth::user()->account->timezone_id) + {!! Button::primary(trans("texts.new_$entityType"))->asLinkTo(URL::to("/{$entityType}s/create"))->appendIcon(Icon::create('plus-sign')) !!} + @endif
    @if (isset($secEntityType)) From 07b3fdb30cee2fde4be6c7986db0cedd9d0b85aa Mon Sep 17 00:00:00 2001 From: Hillel Coren Date: Fri, 7 Aug 2015 09:14:29 +0300 Subject: [PATCH 26/58] Minor improvements --- app/Http/routes.php | 3 +- app/Libraries/Utils.php | 9 +++--- app/Models/Account.php | 1 + app/Ninja/Repositories/AccountRepository.php | 2 +- public/js/built.js | 9 +++--- public/js/pdf.pdfmake.js | 6 ++-- public/js/script.js | 3 -- resources/lang/en/texts.php | 2 ++ resources/views/header.blade.php | 11 ++++--- resources/views/user_account.blade.php | 4 +-- .../views/users/account_management.blade.php | 29 ++++++++++++++++--- 11 files changed, 51 insertions(+), 28 deletions(-) diff --git a/app/Http/routes.php b/app/Http/routes.php index a9c322632db0..706ddbd3bb9e 100644 --- a/app/Http/routes.php +++ b/app/Http/routes.php @@ -1,5 +1,6 @@ id === 1) { Auth::loginUsingId(1); } -*/ +*/ \ No newline at end of file diff --git a/app/Libraries/Utils.php b/app/Libraries/Utils.php index 1efcf4b229a8..1263b4ed6763 100644 --- a/app/Libraries/Utils.php +++ b/app/Libraries/Utils.php @@ -341,10 +341,11 @@ class Utils return; } - $timezone = Session::get(SESSION_TIMEZONE, DEFAULT_TIMEZONE); + //$timezone = Session::get(SESSION_TIMEZONE, DEFAULT_TIMEZONE); $format = Session::get(SESSION_DATE_FORMAT, DEFAULT_DATE_FORMAT); - $dateTime = DateTime::createFromFormat($format, $date, new DateTimeZone($timezone)); + //$dateTime = DateTime::createFromFormat($format, $date, new DateTimeZone($timezone)); + $dateTime = DateTime::createFromFormat($format, $date); return $formatResult ? $dateTime->format('Y-m-d') : $dateTime; } @@ -355,11 +356,11 @@ class Utils return ''; } - $timezone = Session::get(SESSION_TIMEZONE, DEFAULT_TIMEZONE); + //$timezone = Session::get(SESSION_TIMEZONE, DEFAULT_TIMEZONE); $format = Session::get(SESSION_DATE_FORMAT, DEFAULT_DATE_FORMAT); $dateTime = DateTime::createFromFormat('Y-m-d', $date); - $dateTime->setTimeZone(new DateTimeZone($timezone)); + //$dateTime->setTimeZone(new DateTimeZone($timezone)); return $formatResult ? $dateTime->format($format) : $dateTime; } diff --git a/app/Models/Account.php b/app/Models/Account.php index e8cde5293c09..ee88e2fd1fcb 100644 --- a/app/Models/Account.php +++ b/app/Models/Account.php @@ -147,6 +147,7 @@ class Account extends Eloquent public function getLogoPath() { $fileName = 'logo/' . $this->account_key; + return file_exists($fileName.'.png') && $this->utf8_invoices ? $fileName.'.png' : $fileName.'.jpg'; } diff --git a/app/Ninja/Repositories/AccountRepository.php b/app/Ninja/Repositories/AccountRepository.php index 5aaa6e8d4d90..d33c08f7abdf 100644 --- a/app/Ninja/Repositories/AccountRepository.php +++ b/app/Ninja/Repositories/AccountRepository.php @@ -298,7 +298,7 @@ class AccountRepository $item->account_id = $user->account->id; $item->account_name = $user->account->getDisplayName(); $item->pro_plan_paid = $user->account->pro_plan_paid; - $item->account_key = file_exists($user->account->getLogoPath()) ? $user->account->account_key : null; + $item->logo_path = file_exists($user->account->getLogoPath()) ? $user->account->getLogoPath() : null; $data[] = $item; } diff --git a/public/js/built.js b/public/js/built.js index a47d137523b7..08fa79b13021 100644 --- a/public/js/built.js +++ b/public/js/built.js @@ -30748,9 +30748,6 @@ function displayGrid(doc, invoice, data, x, y, layout, options) { key = invoice.account[key]; } else if (key === 'tax' && invoice.tax_name) { key = invoice.tax_name + ' ' + (invoice.tax_rate*1).toString() + '%'; - if (invoice.tax_name.toLowerCase().indexOf(invoiceLabels['tax'].toLowerCase()) == -1) { - key = invoiceLabels['tax'] + ': ' + key; - } } else if (key === 'discount' && NINJA.parseFloat(invoice.discount) && !parseInt(invoice.is_amount_discount)) { key = invoiceLabels[key] + ' ' + parseFloat(invoice.discount) + '%'; } else { @@ -31619,7 +31616,7 @@ NINJA.decodeJavascript = function(invoice, javascript) } // search/replace values - var regExp = new RegExp('"\\$\\\w*?Value"', 'g'); + var regExp = new RegExp('"\\$[\\\w\\\.]*?Value"', 'g'); var matches = javascript.match(regExp); if (matches) { @@ -31628,6 +31625,7 @@ NINJA.decodeJavascript = function(invoice, javascript) field = match.substring(2, match.indexOf('Value')); field = toSnakeCase(field); var value = getDescendantProp(invoice, field) || ' '; + if (field.toLowerCase().indexOf('date') >= 0 && value != ' ') { value = moment(value, 'YYYY-MM-DD').format('MMM D YYYY'); } @@ -31760,7 +31758,8 @@ NINJA.subtotals = function(invoice, removeBalance) } if (invoice.tax && invoice.tax.name || invoice.tax_name) { - data.push([{text: invoiceLabels.tax}, {text: formatMoney(invoice.tax_amount, invoice.client.currency_id)}]); + var taxStr = invoice.tax_name + ' ' + (invoice.tax_rate*1).toString() + '%'; + data.push([{text: taxStr}, {text: formatMoney(invoice.tax_amount, invoice.client.currency_id)}]); } if (NINJA.parseFloat(invoice.custom_value1) && invoice.custom_taxes1 != '1') { diff --git a/public/js/pdf.pdfmake.js b/public/js/pdf.pdfmake.js index 168a8733567b..8ec21c1e5b08 100644 --- a/public/js/pdf.pdfmake.js +++ b/public/js/pdf.pdfmake.js @@ -142,7 +142,7 @@ NINJA.decodeJavascript = function(invoice, javascript) } // search/replace values - var regExp = new RegExp('"\\$\\\w*?Value"', 'g'); + var regExp = new RegExp('"\\$[\\\w\\\.]*?Value"', 'g'); var matches = javascript.match(regExp); if (matches) { @@ -151,6 +151,7 @@ NINJA.decodeJavascript = function(invoice, javascript) field = match.substring(2, match.indexOf('Value')); field = toSnakeCase(field); var value = getDescendantProp(invoice, field) || ' '; + if (field.toLowerCase().indexOf('date') >= 0 && value != ' ') { value = moment(value, 'YYYY-MM-DD').format('MMM D YYYY'); } @@ -283,7 +284,8 @@ NINJA.subtotals = function(invoice, removeBalance) } if (invoice.tax && invoice.tax.name || invoice.tax_name) { - data.push([{text: invoiceLabels.tax}, {text: formatMoney(invoice.tax_amount, invoice.client.currency_id)}]); + var taxStr = invoice.tax_name + ' ' + (invoice.tax_rate*1).toString() + '%'; + data.push([{text: taxStr}, {text: formatMoney(invoice.tax_amount, invoice.client.currency_id)}]); } if (NINJA.parseFloat(invoice.custom_value1) && invoice.custom_taxes1 != '1') { diff --git a/public/js/script.js b/public/js/script.js index eabb1be9f671..221b8d0a0d38 100644 --- a/public/js/script.js +++ b/public/js/script.js @@ -877,9 +877,6 @@ function displayGrid(doc, invoice, data, x, y, layout, options) { key = invoice.account[key]; } else if (key === 'tax' && invoice.tax_name) { key = invoice.tax_name + ' ' + (invoice.tax_rate*1).toString() + '%'; - if (invoice.tax_name.toLowerCase().indexOf(invoiceLabels['tax'].toLowerCase()) == -1) { - key = invoiceLabels['tax'] + ': ' + key; - } } else if (key === 'discount' && NINJA.parseFloat(invoice.discount) && !parseInt(invoice.is_amount_discount)) { key = invoiceLabels[key] + ' ' + parseFloat(invoice.discount) + '%'; } else { diff --git a/resources/lang/en/texts.php b/resources/lang/en/texts.php index 23b684fb2577..1a159cb2c5bb 100644 --- a/resources/lang/en/texts.php +++ b/resources/lang/en/texts.php @@ -742,6 +742,8 @@ return array( 'outstanding' => 'Outstanding', 'manage_companies' => 'Manage Companies', 'total_revenue' => 'Total Revenue', + + 'current_user' => 'Current User', ); diff --git a/resources/views/header.blade.php b/resources/views/header.blade.php index 9abb87690796..6925992c315f 100644 --- a/resources/views/header.blade.php +++ b/resources/views/header.blade.php @@ -385,7 +385,7 @@ 'user_id' => $item->user_id, 'account_name' => $item->account_name, 'user_name' => $item->user_name, - 'account_key' => $item->account_key, + 'logo_path' => isset($item->logo_path) ? $item->logo_path : "", 'selected' => true, ]) @endif @@ -397,7 +397,7 @@ 'user_id' => $item->user_id, 'account_name' => $item->account_name, 'user_name' => $item->user_name, - 'account_key' => $item->account_key, + 'logo_path' => isset($item->logo_path) ? $item->logo_path : "", 'selected' => false, ]) @endif @@ -406,16 +406,15 @@ @include('user_account', [ 'account_name' => Auth::user()->account->name ?: trans('texts.untitled'), 'user_name' => Auth::user()->getDisplayName(), - 'account_key' => Auth::user()->account->account_key, + 'logo_path' => Auth::user()->account->getLogoPath(), 'selected' => true, ]) @endif
  • - @if (!session(SESSION_USER_ACCOUNTS) || count(session(SESSION_USER_ACCOUNTS)) < 5) -
  • {!! link_to('/login?new_company=true', trans('texts.add_company')) !!}
  • - @endif @if (count(session(SESSION_USER_ACCOUNTS)) > 1)
  • {!! link_to('/manage_companies', trans('texts.manage_companies')) !!}
  • + @elseif (!session(SESSION_USER_ACCOUNTS) || count(session(SESSION_USER_ACCOUNTS)) < 5) +
  • {!! link_to('/login?new_company=true', trans('texts.add_company')) !!}
  • @endif
  • {!! link_to('#', trans('texts.logout'), array('onclick'=>'logout()')) !!}
  • diff --git a/resources/views/user_account.blade.php b/resources/views/user_account.blade.php index 9384f621b498..4848a190e5c9 100644 --- a/resources/views/user_account.blade.php +++ b/resources/views/user_account.blade.php @@ -5,9 +5,9 @@
    @endif - @if (file_exists('logo/'.$account_key.'.jpg')) + @if (file_exists($logo_path))
    - +
    @else
     
    diff --git a/resources/views/users/account_management.blade.php b/resources/views/users/account_management.blade.php index 75fa8a500ea7..3839a0bb4377 100644 --- a/resources/views/users/account_management.blade.php +++ b/resources/views/users/account_management.blade.php @@ -2,18 +2,39 @@ @section('content') + +
    + {!! Button::success(trans('texts.add_company'))->asLinkTo('/login?new_company=true') !!} +
    +

     

    +
    +
    +
    +
    +
    - @foreach (Session::get(SESSION_USER_ACCOUNTS) as $account) + @foreach (Session::get(SESSION_USER_ACCOUNTS) as $account) - - - + + + @endforeach
    {{ $account->account_name }}{{ $account->user_name }}{!! Button::primary(trans('texts.unlink'))->small()->withAttributes(['onclick'=>"return showUnlink({$account->id}, {$account->user_id})"]) !!} + @if (isset($account->logo_path)) + {!! HTML::image($account->logo_path.'?no_cache='.time(), 'Logo', ['width' => 100]) !!} + @endif + +

    {{ $account->account_name }}
    + {{ $account->user_name }} + @if ($account->user_id == Auth::user()->id) + | {{ trans('texts.current_user')}} + @endif +

    +
    {!! Button::primary(trans('texts.unlink'))->withAttributes(['onclick'=>"return showUnlink({$account->id}, {$account->user_id})"]) !!}
    From 78bf49cd19fd8f35635ca4266328371eecc88657 Mon Sep 17 00:00:00 2001 From: Hillel Coren Date: Mon, 10 Aug 2015 18:48:41 +0300 Subject: [PATCH 27/58] Recurring invoices no longer prevent invoice numbers from being sequential --- .../Commands/SendRecurringInvoices.php | 73 ++--------------- app/Http/Controllers/InvoiceController.php | 24 +++++- app/Http/Controllers/QuoteController.php | 3 +- app/Http/routes.php | 3 +- app/Models/Client.php | 4 - app/Models/EntityModel.php | 7 +- app/Models/Invoice.php | 11 ++- app/Ninja/Repositories/InvoiceRepository.php | 75 ++++++++++++++++- app/Providers/AppServiceProvider.php | 7 +- ..._122647_add_partial_amount_to_invoices.php | 2 +- public/js/built.js | 4 +- public/js/pdf.pdfmake.js | 4 +- resources/lang/da/texts.php | 7 +- resources/lang/de/texts.php | 7 +- resources/lang/en/texts.php | 7 +- resources/lang/es/texts.php | 7 +- resources/lang/es_ES/texts.php | 7 +- resources/lang/fr/texts.php | 7 +- resources/lang/fr_CA/texts.php | 7 +- resources/lang/it/texts.php | 7 +- resources/lang/lt/texts.php | 7 +- resources/lang/nb_NO/texts.php | 7 +- resources/lang/nl/texts.php | 7 +- resources/lang/pt_BR/texts.php | 7 +- resources/lang/sv/texts.php | 7 +- resources/views/invoices/edit.blade.php | 81 ++++++++++--------- storage/templates/bold.js | 4 +- storage/templates/clean.js | 13 +-- storage/templates/modern.js | 2 +- storage/templates/plain.js | 2 +- 30 files changed, 261 insertions(+), 149 deletions(-) diff --git a/app/Console/Commands/SendRecurringInvoices.php b/app/Console/Commands/SendRecurringInvoices.php index 8f65214f7fc1..8f31473c9eca 100644 --- a/app/Console/Commands/SendRecurringInvoices.php +++ b/app/Console/Commands/SendRecurringInvoices.php @@ -7,6 +7,7 @@ use Illuminate\Console\Command; use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Input\InputArgument; use App\Ninja\Mailers\ContactMailer as Mailer; +use App\Ninja\Repositories\InvoiceRepository; use App\Models\Invoice; use App\Models\InvoiceItem; use App\Models\Invitation; @@ -16,12 +17,14 @@ class SendRecurringInvoices extends Command protected $name = 'ninja:send-invoices'; protected $description = 'Send recurring invoices'; protected $mailer; + protected $invoiceRepo; - public function __construct(Mailer $mailer) + public function __construct(Mailer $mailer, InvoiceRepository $invoiceRepo) { parent::__construct(); $this->mailer = $mailer; + $this->invoiceRepo = $invoiceRepo; } public function fire() @@ -34,74 +37,10 @@ class SendRecurringInvoices extends Command $this->info(count($invoices).' recurring invoice(s) found'); foreach ($invoices as $recurInvoice) { - if ($recurInvoice->client->deleted_at) { - continue; - } - - if (!$recurInvoice->user->confirmed) { - continue; - } - - $this->info('Processing Invoice '.$recurInvoice->id.' - Should send '.($recurInvoice->shouldSendToday() ? 'YES' : 'NO')); - - if (!$recurInvoice->shouldSendToday()) { - continue; - } - - $invoice = Invoice::createNew($recurInvoice); - $invoice->client_id = $recurInvoice->client_id; - $invoice->recurring_invoice_id = $recurInvoice->id; - $invoice->invoice_number = $recurInvoice->account->getNextInvoiceNumber(false, 'R'); - $invoice->amount = $recurInvoice->amount; - $invoice->balance = $recurInvoice->amount; - $invoice->invoice_date = date_create()->format('Y-m-d'); - $invoice->discount = $recurInvoice->discount; - $invoice->po_number = $recurInvoice->po_number; - $invoice->public_notes = Utils::processVariables($recurInvoice->public_notes); - $invoice->terms = Utils::processVariables($recurInvoice->terms); - $invoice->invoice_footer = Utils::processVariables($recurInvoice->invoice_footer); - $invoice->tax_name = $recurInvoice->tax_name; - $invoice->tax_rate = $recurInvoice->tax_rate; - $invoice->invoice_design_id = $recurInvoice->invoice_design_id; - $invoice->custom_value1 = $recurInvoice->custom_value1; - $invoice->custom_value2 = $recurInvoice->custom_value2; - $invoice->custom_taxes1 = $recurInvoice->custom_taxes1; - $invoice->custom_taxes2 = $recurInvoice->custom_taxes2; - $invoice->is_amount_discount = $recurInvoice->is_amount_discount; - - if ($invoice->client->payment_terms != 0) { - $days = $invoice->client->payment_terms; - if ($days == -1) { - $days = 0; - } - $invoice->due_date = date_create()->modify($days.' day')->format('Y-m-d'); - } - - $invoice->save(); - - foreach ($recurInvoice->invoice_items as $recurItem) { - $item = InvoiceItem::createNew($recurItem); - $item->product_id = $recurItem->product_id; - $item->qty = $recurItem->qty; - $item->cost = $recurItem->cost; - $item->notes = Utils::processVariables($recurItem->notes); - $item->product_key = Utils::processVariables($recurItem->product_key); - $item->tax_name = $recurItem->tax_name; - $item->tax_rate = $recurItem->tax_rate; - $invoice->invoice_items()->save($item); - } - - foreach ($recurInvoice->invitations as $recurInvitation) { - $invitation = Invitation::createNew($recurInvitation); - $invitation->contact_id = $recurInvitation->contact_id; - $invitation->invitation_key = str_random(RANDOM_KEY_LENGTH); - $invoice->invitations()->save($invitation); - } + $this->info('Processing Invoice '.$recurInvoice->id.' - Should send '.($recurInvoice->shouldSendToday() ? 'YES' : 'NO')); + $this->invoiceRepo->createRecurringInvoice($recurInvoice); $this->mailer->sendInvoice($invoice); - - $recurInvoice->last_sent_date = Carbon::now()->toDateTimeString(); - $recurInvoice->save(); } $this->info('Done'); diff --git a/app/Http/Controllers/InvoiceController.php b/app/Http/Controllers/InvoiceController.php index 248b1be6bef3..efed3effd150 100644 --- a/app/Http/Controllers/InvoiceController.php +++ b/app/Http/Controllers/InvoiceController.php @@ -280,7 +280,7 @@ class InvoiceController extends BaseController $method = 'POST'; $url = "{$entityType}s"; } else { - Utils::trackViewed($invoice->invoice_number.' - '.$invoice->client->getDisplayName(), $invoice->getEntityType()); + Utils::trackViewed($invoice->getDisplayName().' - '.$invoice->client->getDisplayName(), $invoice->getEntityType()); $method = 'PUT'; $url = "{$entityType}s/{$publicId}"; } @@ -335,6 +335,7 @@ class InvoiceController extends BaseController 'url' => $url, 'title' => trans("texts.edit_{$entityType}"), 'client' => $invoice->client, + 'isRecurring' => $invoice->is_recurring, 'actions' => $actions); $data = array_merge($data, self::getViewModel()); @@ -358,10 +359,10 @@ class InvoiceController extends BaseController return View::make('invoices.edit', $data); } - public function create($clientPublicId = 0) + public function create($clientPublicId = 0, $isRecurring = false) { $client = null; - $invoiceNumber = Auth::user()->account->getNextInvoiceNumber(); + $invoiceNumber = $isRecurring ? microtime(true) : Auth::user()->account->getNextInvoiceNumber(); if ($clientPublicId) { $client = Client::scope($clientPublicId)->firstOrFail(); @@ -375,12 +376,18 @@ class InvoiceController extends BaseController 'method' => 'POST', 'url' => 'invoices', 'title' => trans('texts.new_invoice'), + 'isRecurring' => $isRecurring, 'client' => $client); $data = array_merge($data, self::getViewModel()); return View::make('invoices.edit', $data); } + public function createRecurring($clientPublicId = 0) + { + return self::create($clientPublicId, true); + } + private static function getViewModel() { $recurringHelp = ''; @@ -510,7 +517,16 @@ class InvoiceController extends BaseController return $this->convertQuote($publicId); } elseif ($action == 'email') { if (Auth::user()->confirmed && !Auth::user()->isDemo()) { - $response = $this->mailer->sendInvoice($invoice); + if ($invoice->is_recurring) { + if ($invoice->shouldSendToday()) { + $invoice = $this->invoiceRepo->createRecurringInvoice($invoice); + $response = $this->mailer->sendInvoice($invoice); + } else { + $response = trans('texts.recurring_too_soon'); + } + } else { + $response = $this->mailer->sendInvoice($invoice); + } if ($response === true) { $message = trans("texts.emailed_{$entityType}"); Session::flash('message', $message); diff --git a/app/Http/Controllers/QuoteController.php b/app/Http/Controllers/QuoteController.php index bb8526c424e9..589841a314bf 100644 --- a/app/Http/Controllers/QuoteController.php +++ b/app/Http/Controllers/QuoteController.php @@ -158,7 +158,8 @@ class QuoteController extends BaseController 'paymentTerms' => Cache::get('paymentTerms'), 'industries' => Cache::get('industries'), 'invoiceDesigns' => InvoiceDesign::getDesigns(), - 'invoiceLabels' => Auth::user()->account->getInvoiceLabels() + 'invoiceLabels' => Auth::user()->account->getInvoiceLabels(), + 'isRecurring' => false, ]; } diff --git a/app/Http/routes.php b/app/Http/routes.php index 706ddbd3bb9e..7c158a314490 100644 --- a/app/Http/routes.php +++ b/app/Http/routes.php @@ -1,6 +1,5 @@ 'auth'], function() { Route::get('tasks/create/{client_id?}', 'TaskController@create'); Route::post('tasks/bulk', 'TaskController@bulk'); - Route::get('recurring_invoices', 'InvoiceController@recurringIndex'); Route::get('api/recurring_invoices/{client_id?}', array('as'=>'api.recurring_invoices', 'uses'=>'InvoiceController@getRecurringDatatable')); Route::get('invoices/invoice_history/{invoice_id}', 'InvoiceController@invoiceHistory'); @@ -141,6 +139,7 @@ Route::group(['middleware' => 'auth'], function() { Route::resource('invoices', 'InvoiceController'); Route::get('api/invoices/{client_id?}', array('as'=>'api.invoices', 'uses'=>'InvoiceController@getDatatable')); Route::get('invoices/create/{client_id?}', 'InvoiceController@create'); + Route::get('recurring_invoices/create/{client_id?}', 'InvoiceController@createRecurring'); Route::get('invoices/{public_id}/clone', 'InvoiceController@cloneInvoice'); Route::post('invoices/bulk', 'InvoiceController@bulk'); diff --git a/app/Models/Client.php b/app/Models/Client.php index a9b6c8fe95d3..554f74556910 100644 --- a/app/Models/Client.php +++ b/app/Models/Client.php @@ -83,10 +83,6 @@ class Client extends EntityModel return $this->name; } - if (!$this->contacts || !count($this->contacts)) { - $this->load('contacts'); - } - $contact = $this->contacts()->first(); return $contact->getDisplayName(); diff --git a/app/Models/EntityModel.php b/app/Models/EntityModel.php index bf44b6f6d886..550de1d3cef0 100644 --- a/app/Models/EntityModel.php +++ b/app/Models/EntityModel.php @@ -44,7 +44,7 @@ class EntityModel extends Eloquent public function getActivityKey() { - return '[' . $this->getEntityType().':'.$this->public_id.':'.$this->getName() . ']'; + return '[' . $this->getEntityType().':'.$this->public_id.':'.$this->getDisplayName() . ']'; } /* @@ -83,6 +83,11 @@ class EntityModel extends Eloquent return $this->public_id; } + public function getDisplayName() + { + return $this->getName(); + } + // Remap ids to public_ids and show name public function toPublicArray() { diff --git a/app/Models/Invoice.php b/app/Models/Invoice.php index 63700410fa18..aeebfaed6ab0 100644 --- a/app/Models/Invoice.php +++ b/app/Models/Invoice.php @@ -48,6 +48,11 @@ class Invoice extends EntityModel return $this->belongsTo('App\Models\Invoice'); } + public function recurring_invoices() + { + return $this->hasMany('App\Models\Invoice', 'recurring_invoice_id'); + } + public function invitations() { return $this->hasMany('App\Models\Invitation')->orderBy('invitations.contact_id'); @@ -55,7 +60,7 @@ class Invoice extends EntityModel public function getName() { - return $this->invoice_number; + return $this->is_recurring ? trans('texts.recurring') : $this->invoice_number; } public function getFileName() @@ -258,7 +263,9 @@ class Invoice extends EntityModel } Invoice::creating(function ($invoice) { - $invoice->account->incrementCounter($invoice->is_quote); + if (!$invoice->is_recurring) { + $invoice->account->incrementCounter($invoice->is_quote); + } }); Invoice::created(function ($invoice) { diff --git a/app/Ninja/Repositories/InvoiceRepository.php b/app/Ninja/Repositories/InvoiceRepository.php index e93ea47826bb..bfbf62658f45 100644 --- a/app/Ninja/Repositories/InvoiceRepository.php +++ b/app/Ninja/Repositories/InvoiceRepository.php @@ -1,11 +1,12 @@ select(['public_id', 'invoice_number']) ->get(); } + + public function createRecurringInvoice($recurInvoice) + { + $recurInvoice->load('account.timezone', 'invoice_items', 'client', 'user'); + + if ($recurInvoice->client->deleted_at) { + return false; + } + + if (!$recurInvoice->user->confirmed) { + return false; + } + + if (!$recurInvoice->shouldSendToday()) { + return false; + } + + $invoice = Invoice::createNew($recurInvoice); + $invoice->client_id = $recurInvoice->client_id; + $invoice->recurring_invoice_id = $recurInvoice->id; + $invoice->invoice_number = $recurInvoice->account->getNextInvoiceNumber(false, 'R'); + $invoice->amount = $recurInvoice->amount; + $invoice->balance = $recurInvoice->amount; + $invoice->invoice_date = date_create()->format('Y-m-d'); + $invoice->discount = $recurInvoice->discount; + $invoice->po_number = $recurInvoice->po_number; + $invoice->public_notes = Utils::processVariables($recurInvoice->public_notes); + $invoice->terms = Utils::processVariables($recurInvoice->terms); + $invoice->invoice_footer = Utils::processVariables($recurInvoice->invoice_footer); + $invoice->tax_name = $recurInvoice->tax_name; + $invoice->tax_rate = $recurInvoice->tax_rate; + $invoice->invoice_design_id = $recurInvoice->invoice_design_id; + $invoice->custom_value1 = $recurInvoice->custom_value1; + $invoice->custom_value2 = $recurInvoice->custom_value2; + $invoice->custom_taxes1 = $recurInvoice->custom_taxes1; + $invoice->custom_taxes2 = $recurInvoice->custom_taxes2; + $invoice->is_amount_discount = $recurInvoice->is_amount_discount; + + if ($invoice->client->payment_terms != 0) { + $days = $invoice->client->payment_terms; + if ($days == -1) { + $days = 0; + } + $invoice->due_date = date_create()->modify($days.' day')->format('Y-m-d'); + } + + $invoice->save(); + + foreach ($recurInvoice->invoice_items as $recurItem) { + $item = InvoiceItem::createNew($recurItem); + $item->product_id = $recurItem->product_id; + $item->qty = $recurItem->qty; + $item->cost = $recurItem->cost; + $item->notes = Utils::processVariables($recurItem->notes); + $item->product_key = Utils::processVariables($recurItem->product_key); + $item->tax_name = $recurItem->tax_name; + $item->tax_rate = $recurItem->tax_rate; + $invoice->invoice_items()->save($item); + } + + foreach ($recurInvoice->invitations as $recurInvitation) { + $invitation = Invitation::createNew($recurInvitation); + $invitation->contact_id = $recurInvitation->contact_id; + $invitation->invitation_key = str_random(RANDOM_KEY_LENGTH); + $invoice->invitations()->save($invitation); + } + + $recurInvoice->last_sent_date = Carbon::now()->toDateTimeString(); + $recurInvoice->save(); + + return $invoice; + } } diff --git a/app/Providers/AppServiceProvider.php b/app/Providers/AppServiceProvider.php index 9efba90b91af..d9fc74798f69 100644 --- a/app/Providers/AppServiceProvider.php +++ b/app/Providers/AppServiceProvider.php @@ -40,10 +40,13 @@ class AppServiceProvider extends ServiceProvider {