From f9925e0486a04157bd279eaed98ed9b473c22147 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Mon, 11 Sep 2023 09:51:52 +1000 Subject: [PATCH 01/20] Set default notifications on initial account creation --- app/DataMapper/CompanySettings.php | 17 ++++ app/Jobs/User/CreateUser.php | 2 +- lang/fr_CA/texts.php | 145 +++++++++++++++-------------- 3 files changed, 92 insertions(+), 72 deletions(-) diff --git a/app/DataMapper/CompanySettings.php b/app/DataMapper/CompanySettings.php index 5a957a8f8fcd..99638a0fa981 100644 --- a/app/DataMapper/CompanySettings.php +++ b/app/DataMapper/CompanySettings.php @@ -843,6 +843,23 @@ class CompanySettings extends BaseSettings return $notification; } + /** + * Stubs the notification defaults + * + * @return stdClass + */ + public static function notificationAdminDefaults() :stdClass + { + $notification = new stdClass; + $notification->email = []; + $notification->email = ['invoice_sent_all']; + + return $notification; + } + + + + /** * Defines entity variables for PDF generation * diff --git a/app/Jobs/User/CreateUser.php b/app/Jobs/User/CreateUser.php index 3e33c6f6c28c..698f32b48ca4 100644 --- a/app/Jobs/User/CreateUser.php +++ b/app/Jobs/User/CreateUser.php @@ -76,7 +76,7 @@ class CreateUser 'is_admin' => 1, 'is_locked' => 0, 'permissions' => '', - 'notifications' => CompanySettings::notificationDefaults(), + 'notifications' => CompanySettings::notificationAdminDefaults(), 'settings' => null, ]); diff --git a/lang/fr_CA/texts.php b/lang/fr_CA/texts.php index e0711005e38c..fa47b7c1da3f 100644 --- a/lang/fr_CA/texts.php +++ b/lang/fr_CA/texts.php @@ -133,7 +133,7 @@ $LANG = array( 'balance' => 'Solde', 'action' => 'Action', 'status' => 'État', - 'invoice_total' => 'Montant total', + 'invoice_total' => 'Total de facture', 'frequency' => 'Fréquence', 'range' => 'Période', 'start_date' => 'Date de début', @@ -289,7 +289,7 @@ $LANG = array( 'fill_products_help' => 'La sélection d\'un produit entrainera la mise à jour de la description et du prix', 'update_products' => 'Mise à jour automatique des produits', 'update_products_help' => 'La mise à jour d\'une facture entraîne la mise à jour des produits', - 'create_product' => 'Nouveau produit', + 'create_product' => 'Ajouter un produit', 'edit_product' => 'Modifier le produit', 'archive_product' => 'Archiver le produit', 'updated_product' => 'Le produit a été mis à jour', @@ -320,7 +320,7 @@ $LANG = array( 'delete_quote' => 'Supprimer la soumission', 'save_quote' => 'Enregistrer la soumission', 'email_quote' => 'Envoyer la soumission par courriel', - 'clone_quote' => 'Dupliquer vers une nouvelle soumission', + 'clone_quote' => 'Dupliquer en soumission', 'convert_to_invoice' => 'Convertir en facture', 'view_invoice' => 'Voir la facture', 'view_client' => 'Voir le client', @@ -433,7 +433,7 @@ $LANG = array( 'token_billing_type_id' => 'Jeton de facturation', 'token_billing_help' => 'Enregistrez les informations de paiement avec WePay, Stripe, Braintree ou GoCardless.', 'token_billing_1' => 'Désactivé', - 'token_billing_2' => 'Adhérer - case à cocher affichée et non sélectionner', + 'token_billing_2' => 'Adhérer - case à cocher affichée et non sélectionnée', 'token_billing_3' => 'Se soustraire - case à cocher affichée et sélectionnée', 'token_billing_4' => 'Toujours', 'token_billing_checkbox' => 'Mémoriser les informations de carte de crédit', @@ -450,7 +450,7 @@ $LANG = array( 'billing_method' => 'Méthode de facturation', 'order_overview' => 'Récapitulatif de la commande', 'match_address' => '*L\'adresse doit correspondre à l\'adresse associée à la carte de crédit.', - 'click_once' => '*Please click "PAY NOW" only once - transaction may take up to 1 minute to process.', + 'click_once' => '*Veuillez cliquer sur "PAYER MAINTENANT" une seule fois - la transaction peut prendre jusqu\'à 1 minute.', 'invoice_footer' => 'Pied de facture', 'save_as_default_footer' => 'Sauvegarder comme pied de facture par défaut', 'token_management' => 'Gestion des jetons', @@ -492,7 +492,7 @@ $LANG = array( 'email_approved' => 'M\'envoyer un courriel lorsqu\'une soumission a été acceptée', 'notification_quote_approved_subject' => 'La soumission :invoice a été acceptée par :client', 'notification_quote_approved' => 'Le client :client a accepté la soumission :invoice pour :amount.', - 'resend_confirmation' => 'Renvoyer la confirmation par courriel', + 'resend_confirmation' => 'Renvoyer le courriel de confirmation', 'confirmation_resent' => 'La confirmation a été renvoyée', 'payment_type_credit_card' => 'Carte de crédit', 'payment_type_paypal' => 'PayPal', @@ -560,8 +560,8 @@ $LANG = array( 'time_log' => 'Journal de temps', 'end_time' => 'Arrêtée à', 'end' => 'Fin', - 'invoiced' => 'Facturée', - 'logged' => 'Enregistrée', + 'invoiced' => 'Facturé', + 'logged' => 'Connecté', 'running' => 'En cours', 'task_error_multiple_clients' => 'Une tâche ne peut appartenir à plusieurs clients', 'task_error_running' => 'Merci d\'arrêter les tâches en cours', @@ -663,10 +663,10 @@ $LANG = array( 'invoice_sent' => ':count facture envoyée', 'invoices_sent' => ':count factures envoyées', 'status_draft' => 'Brouillon', - 'status_sent' => 'Envoyée', + 'status_sent' => 'Envoyé', 'status_viewed' => 'Consulté', 'status_partial' => 'Partiel', - 'status_paid' => 'Payée', + 'status_paid' => 'Payé', 'status_unpaid' => 'Impayé', 'status_all' => 'Tous', 'show_line_item_tax' => 'Afficher la taxe sur la même ligne', @@ -681,8 +681,8 @@ $LANG = array( 'templates_and_reminders' => 'Modèles et rappels', 'subject' => 'Sujet', 'body' => 'Corps', - 'first_reminder' => '1er rappel', - 'second_reminder' => '2e rappel', + 'first_reminder' => 'Premier rappel', + 'second_reminder' => 'Deuxième rappel', 'third_reminder' => 'Troisième rappel', 'num_days_reminder' => 'Jours après la date d\'échéance', 'reminder_subject' => 'Rappel: facture :invoice de :account', @@ -885,7 +885,7 @@ $LANG = array( 'days_before' => 'jours avant le', 'days_after' => 'jours après le', 'field_due_date' => 'Échéance', - 'field_invoice_date' => 'date de la facture', + 'field_invoice_date' => 'date de facturation', 'schedule' => 'Planification', 'email_designs' => 'Modèles de courriel', 'assigned_when_sent' => 'Assignée lors de l\'envoi', @@ -930,7 +930,7 @@ $LANG = array( 'convert_currency' => 'Conversion de devise', 'num_days' => 'Nombre de jours', 'create_payment_term' => 'Nouveau délai de paiement', - 'edit_payment_terms' => 'Modifier les délais de paiement', + 'edit_payment_terms' => 'Modifier le délai de paiement', 'edit_payment_term' => 'Modifier le délai de paiement', 'archive_payment_term' => 'Archiver le délai de paiement', 'recurring_due_dates' => 'Dates d\'échéances des factures récurrentes', @@ -984,7 +984,7 @@ $LANG = array( 'account_number' => 'N° du compte', 'account_name' => 'Nom du compte', 'bank_account_error' => 'Impossible de récupérer les informations de compte, veuillez vérifier les informations entrées.', - 'status_approved' => 'Acceptée', + 'status_approved' => 'Approuvé', 'quote_settings' => 'Paramètres des soumissions', 'auto_convert_quote' => 'Conversion automatique', 'auto_convert_quote_help' => 'Convertir automatiquement une soumission lorsque celle-ci est approuvée.', @@ -996,7 +996,7 @@ $LANG = array( 'expense_error_mismatch_currencies' => 'La devise du client ne correspond par à la devise de la dépense.', 'trello_roadmap' => 'Feuille de route Trello', 'header_footer' => 'En-tête / pied de page', - 'first_page' => 'première page', + 'first_page' => 'Première page', 'all_pages' => 'toutes les pages', 'last_page' => 'dernière page', 'all_pages_header' => 'Afficher l\'en-tête sur', @@ -1009,7 +1009,7 @@ $LANG = array( 'trial_message' => 'Vous allez bénéficier d\'un essai gratuit de 2 semaines au Plan Pro.', 'trial_footer' => 'Vous avez encore :count jours pour votre essai gratuit Pro Plan, :link pour s\'inscrire.', 'trial_footer_last_day' => 'C\'est le dernier jour de votre essai gratuit Pro Plan, :link pour s\'inscrire.', - 'trial_call_to_action' => 'Démarrez votre essai gratuit', + 'trial_call_to_action' => 'Démarrer la période d\'essai', 'trial_success' => 'Le Plan Pro, version d\'essai gratuit pour 2 semaines a été activé', 'overdue' => 'En souffrance', @@ -1113,7 +1113,7 @@ $LANG = array( 'expense_documents' => 'Justificatifs de dépense', 'invoice_embed_documents' => 'Documents intégrés', 'invoice_embed_documents_help' => 'Inclure les images jointes dans la facture.', - 'document_email_attachment' => 'Documents joints', + 'document_email_attachment' => 'Joindre un document', 'ubl_email_attachment' => 'Joindre un UBL', 'download_documents' => 'Télécharger les documents (:size)', 'documents_from_expenses' => 'Des dépenses:', @@ -1198,8 +1198,8 @@ $LANG = array( 'refund' => 'Rembousement', 'are_you_sure_refund' => 'Rembourser les paiements sélectionnés?', 'status_pending' => 'En attente', - 'status_completed' => 'Terminée', - 'status_failed' => 'Échouée', + 'status_completed' => 'Complété', + 'status_failed' => 'Échoué', 'status_partially_refunded' => 'Remboursement partiel', 'status_partially_refunded_amount' => ':amount remboursé', 'status_refunded' => 'Remboursé', @@ -1286,8 +1286,8 @@ Lorsque les montant apparaîtront sur votre relevé, veuillez revenir sur cette 'ach_authorization' => 'J\'autorise :company à utiliser mon compte bancaire pour les paiements futurs et, si nécessaire, créditer électroniquement mon compte pour corriger d\'éventuels débits erronés. Je comprends que je peux annuler cette autorisation à tout moment en supprimant le mode de paiement ou en contactant :email.', 'ach_authorization_required' => 'Vous devez consentir aux transactions ACH.', 'off' => 'Désactivé', - 'opt_in' => 'Activer', - 'opt_out' => 'Désactiver', + 'opt_in' => 'Adhérer', + 'opt_out' => 'Désadhérer', 'always' => 'Toujours', 'opted_out' => 'Désactivé', 'opted_in' => 'Activé', @@ -1325,8 +1325,8 @@ Lorsque les montant apparaîtront sur votre relevé, veuillez revenir sur cette 'created_wepay_confirmation_required' => 'Veuillez vérifier vos courriel et confirmer votre adresse courriel avec WePay.', 'switch_to_wepay' => 'Changer pour WePay', 'switch' => 'Commutateur', - 'restore_account_gateway' => 'Restaurer la passerelle de paiement', - 'restored_account_gateway' => 'La passerelle de paiement a été restaurée', + 'restore_account_gateway' => 'Restaurer la passerelle', + 'restored_account_gateway' => 'La passerelle a été restaurée', 'united_states' => 'États-Unis', 'canada' => 'Canada', 'accept_debit_cards' => 'Accepter les cartes de débit', @@ -1398,11 +1398,11 @@ Lorsque les montant apparaîtront sur votre relevé, veuillez revenir sur cette 'freq_biweekly' => 'Bihebdomadaire', 'freq_two_weeks' => 'Aux deux semaines', 'freq_four_weeks' => 'Aux quatre semaines', - 'freq_monthly' => 'Mensuelle', + 'freq_monthly' => 'Mensuel', 'freq_three_months' => 'Trimestrielle', 'freq_four_months' => '4 mois', 'freq_six_months' => 'Semestrielle', - 'freq_annually' => 'Annuelle', + 'freq_annually' => 'Annuellement', 'freq_two_years' => 'Deux ans', // Payment types @@ -1813,7 +1813,7 @@ Lorsque les montant apparaîtront sur votre relevé, veuillez revenir sur cette 'bot_emailed_notify_paid' => 'Recevez un courriel lorsqu\'elle sera payée.', 'add_product_to_invoice' => 'Ajouter 1 :product', 'not_authorized' => 'Vous n\'êtes pas autorisé', - 'bot_get_email' => 'Salut! (wave)
Merci d\'essayer le Bot de Invoice Ninja.
Envoie-moi l\'adresse courriel de ton compte pour commencer.', + 'bot_get_email' => 'Bonjour! (wave)
Thanks for trying the Invoice Ninja Bot.
Vous devez vous créer un compte gratuit pour utiliser ce bot.
Veuillez envoyer votre adresse courriel associée à votre compte pour démarrer.', 'bot_get_code' => 'Merci! Je vous ai envoyé un courriel avec votre code de sécurité.', 'bot_welcome' => 'Ça y est, votre compte est maintenant vérifié.>br/>', 'email_not_found' => 'Je n\'ai pas pu trouver un compte disponible pour :email', @@ -1973,12 +1973,12 @@ Lorsque les montant apparaîtront sur votre relevé, veuillez revenir sur cette 'toggle_menu' => 'Basculer la navigation', 'new_...' => 'Nouveau ...', 'list_...' => 'Liste ...', - 'created_at' => 'Créé le', + 'created_at' => 'Date de création', 'contact_us' => 'Nous joindre', 'user_guide' => 'Guide de l\'utilisateur', 'promo_message' => 'Profitez de l\'offre avant le :expires et épargnez :amount sur la première année de notre plan Pro ou Entreprise.', 'discount_message' => 'L\'offre de :amount expire le :expires', - 'mark_paid' => 'Marquer comme payée', + 'mark_paid' => 'Marquer comme payé', 'marked_sent_invoice' => 'La facture marquée a été envoyée', 'marked_sent_invoices' => 'Les factures marquées ont été envoyées', 'invoice_name' => 'Facture', @@ -2046,7 +2046,7 @@ Lorsque les montant apparaîtront sur votre relevé, veuillez revenir sur cette 'age_group_120' => '120+ jours', 'invoice_details' => 'Informations de facture', 'qty' => 'Quantité', - 'profit_and_loss' => 'Profit et perte', + 'profit_and_loss' => 'Bénéfice et perte', 'revenue' => 'Revenu', 'profit' => 'Profit', 'group_when_sorted' => 'Trier par groupe', @@ -2120,8 +2120,8 @@ Lorsque les montant apparaîtront sur votre relevé, veuillez revenir sur cette 'location' => 'Endroit', 'line_item' => 'Ligne d\'article', 'surcharge' => 'surcharge', - 'location_first_surcharge' => 'Activer - Première surcharge', - 'location_second_surcharge' => 'Activer - Deuxième surcharge', + 'location_first_surcharge' => 'Activée - Première surcharge', + 'location_second_surcharge' => 'Activée - Deuxième surcharge', 'location_line_item' => 'Activer - Ligne d\'article', 'online_payment_surcharge' => 'Surcharge de paiement en ligne', 'gateway_fees' => 'Frais de passerelle', @@ -2408,12 +2408,12 @@ Lorsque les montant apparaîtront sur votre relevé, veuillez revenir sur cette 'tax2' => 'Deuxième taxe', 'fee_help' => 'Les frais de la passerelle sont les coûts facturés pour l\'accès aux réseaux financiers qui traitent le traitement des paiements en ligne.', 'format_export' => 'Format d\'exportation', - 'custom1' => 'Personnalisation 1', - 'custom2' => 'Personnalisation 2', + 'custom1' => 'Première personnalisation', + 'custom2' => 'Dexième personnalisation', 'contact_first_name' => 'Prénom du contact', 'contact_last_name' => 'Nom du contact', - 'contact_custom1' => 'Personnalisation 1 du contact', - 'contact_custom2' => 'Personnalisation 2 du contact', + 'contact_custom1' => 'Première personnalisation du contact', + 'contact_custom2' => 'Deuxième personnalisation du contact', 'currency' => 'Devise', 'ofx_help' => 'Pour résoudre un problème, consultez les commentaires sur :ofxhome_link et testez avec :ofxget_link.', 'comments' => 'commentaires', @@ -2721,7 +2721,7 @@ Lorsque les montant apparaîtront sur votre relevé, veuillez revenir sur cette 'icon' => 'Icône', 'proposal_not_found' => 'La proposition demandée n\'est pas accessible', 'create_proposal_category' => 'Créer une catégorie', - 'clone_proposal_template' => 'Cloner un modèle', + 'clone_proposal_template' => 'Dupliquer un modèle', 'proposal_email' => 'Courriel de proposition', 'proposal_subject' => 'Nouvelle proposition :number pour :account', 'proposal_message' => 'Pour visualiser votre proposition de :amount, suivez le lien ci-dessous.', @@ -2751,10 +2751,10 @@ Lorsque les montant apparaîtront sur votre relevé, veuillez revenir sur cette 'reactivate' => 'Réactiver', 'reactivated_email' => 'L\'adresse courriel a été réactivée', 'emails' => 'Courriels', - 'opened' => 'Ouverts', + 'opened' => 'Ouvert', 'bounced' => 'Rejetés', 'total_sent' => 'Total envoyés', - 'total_opened' => 'Total ouverts', + 'total_opened' => 'Total ouvert', 'total_bounced' => 'Total rejetés', 'total_spam' => 'Total pourriels', 'platforms' => 'Plateformes', @@ -2788,7 +2788,7 @@ Lorsque les montant apparaîtront sur votre relevé, veuillez revenir sur cette 'purge_client' => 'Purger client', 'purged_client' => 'Le client a été purgé', 'purge_client_warning' => 'Tous les enregistrements (factures, tâches, dépenses, documents, etc...) seront aussi supprimés.', - 'clone_product' => 'Cloner le produit', + 'clone_product' => 'Dupliquer le produit', 'item_details' => 'Détails de l\'article', 'send_item_details_help' => 'Envoyer les détails de l\'article à la passerelle de paiement.', 'view_proposal' => 'Voir la proposition', @@ -2875,20 +2875,20 @@ Lorsque les montant apparaîtront sur votre relevé, veuillez revenir sur cette 'please_enter_a_quote_number' => 'Veuillez saisir un numéro de soumission', 'clients_invoices' => 'Factures de :client\'s', 'viewed' => 'Consulté', - 'approved' => 'Approuvée', + 'approved' => 'Approuvé', 'invoice_status_1' => 'Brouillon', - 'invoice_status_2' => 'Envoyée', + 'invoice_status_2' => 'Envoyé', 'invoice_status_3' => 'Consulté', - 'invoice_status_4' => 'Approuvée', - 'invoice_status_5' => 'Partielle', - 'invoice_status_6' => 'Payée', + 'invoice_status_4' => 'Approuvé', + 'invoice_status_5' => 'Partiel', + 'invoice_status_6' => 'Payé', 'marked_invoice_as_sent' => 'La facture a été marquée comme envoyée', 'please_enter_a_client_or_contact_name' => 'Veuillez saisir un nom de client ou de contact', 'restart_app_to_apply_change' => 'Redémarrez l\'app pour mettre à jour les changements', 'refresh_data' => 'Actualiser les données', 'blank_contact' => 'Contact vide', 'no_records_found' => 'Aucun enregistrement trouvé', - 'industry' => 'Entreprise', + 'industry' => 'Secteur d\'activité', 'size' => 'Taille', 'net' => 'Net', 'show_tasks' => 'Afficher les tâches', @@ -2908,9 +2908,9 @@ Lorsque les montant apparaîtront sur votre relevé, veuillez revenir sur cette 'payment_status' => 'État du paiement', 'payment_status_1' => 'Em attente', 'payment_status_2' => 'Annulée', - 'payment_status_3' => 'Échouée', - 'payment_status_4' => 'Complétée', - 'payment_status_5' => 'Partiellement remboursée', + 'payment_status_3' => 'Échoué', + 'payment_status_4' => 'Complété', + 'payment_status_5' => 'Remboursement partiel', 'payment_status_6' => 'Remboursé', 'send_receipt_to_client' => 'Envoyer un reçu au client', 'refunded' => 'Remboursé', @@ -3057,14 +3057,14 @@ Lorsque les montant apparaîtront sur votre relevé, veuillez revenir sur cette 'previous_year' => 'Année précédente', 'compare_to' => 'Comparer à', 'last_week' => 'Dernière semaine', - 'clone_to_invoice' => 'Cloner en facture', - 'clone_to_quote' => 'Cloner en soumission', + 'clone_to_invoice' => 'Dupliquer en facture', + 'clone_to_quote' => 'Dupliquer en soumission', 'convert' => 'Convertir', 'last7_days' => '7 derniers jours', 'last30_days' => '30 derniers jours', 'custom_js' => 'JS personnalisé', 'adjust_fee_percent_help' => 'Ajuster le frais de pourcentage au compte', - 'show_product_notes' => 'Afficher le détail des produits', + 'show_product_notes' => 'Afficher les détails du produit', 'show_product_notes_help' => 'Inclure la description et le coût dans le menu déroulant du produit', 'important' => 'Important', 'thank_you_for_using_our_app' => 'Merci d\'utiliser notre app!', @@ -3117,7 +3117,7 @@ Lorsque les montant apparaîtront sur votre relevé, veuillez revenir sur cette 'please_agree_to_terms_and_privacy' => 'Vous devez accepter les conditions et la politique de confidentialité pour créer un compte.', 'i_agree_to_the' => 'J\'accepte', 'terms_of_service_link' => 'les conditions', - 'privacy_policy_link' => 'la politique de confidentialité', + 'privacy_policy_link' => 'politique de confidentialité', 'view_website' => 'Visiter le site web', 'create_account' => 'Créer un compte', 'email_login' => 'Courriel de connexion', @@ -3143,7 +3143,7 @@ Lorsque les montant apparaîtront sur votre relevé, veuillez revenir sur cette 'portal_mode' => 'Mode portail', 'attach_pdf' => 'Joindre un PDF', 'attach_documents' => 'Joindre un document', - 'attach_ubl' => 'Joindre UBL', + 'attach_ubl' => 'Joindre un UBL', 'email_style' => 'Style de courriel', 'processed' => 'Traité', 'fee_amount' => 'Montant des frais', @@ -3301,8 +3301,8 @@ Lorsque les montant apparaîtront sur votre relevé, veuillez revenir sur cette 'tablet' => 'Tablette', 'layout' => 'Affichage', 'module' => 'Module', - 'first_custom' => 'Premier personnalisé', - 'second_custom' => 'Second personnalisé', + 'first_custom' => 'Première personnalisation', + 'second_custom' => 'Deuxième personnalisation', 'third_custom' => 'Troisième rappel', 'show_cost' => 'Afficher le coût', 'show_cost_help' => 'Afficher un champ de coût du produit pour suivre le profit', @@ -3459,14 +3459,14 @@ Lorsque les montant apparaîtront sur votre relevé, veuillez revenir sur cette 'slack_webhook_url' => 'URL du Webhook Slack', 'partial_payment' => 'Paiement partiel', 'partial_payment_email' => 'Courriel du paiement partiel', - 'clone_to_credit' => 'Cloner au crédit', + 'clone_to_credit' => 'Dupliquer en crédit', 'emailed_credit' => 'Le crédit a envoyé par courriel', 'marked_credit_as_sent' => 'Le crédit a été marqué comme envoyé', 'email_subject_payment_partial' => 'Sujet du courriel de paiement partiel', 'is_approved' => 'Est approuvé', 'migration_went_wrong' => 'Oups, quelque chose n\'a pas bien fonctionné! Veuillez vous assurer que vous avez bien configuré une instance de Invoice Ninja v5 avant de commencer la migration.', 'cross_migration_message' => 'La migration entre comptes n\'est pas autorisée. Pour en savoir plus: https://invoiceninja.github.io/docs/migration/#troubleshooting', - 'email_credit' => 'Crédit par courriel', + 'email_credit' => 'Envoyer le crédit par courriel', 'client_email_not_set' => 'Le client n\'a pas d\'adresse courriel définie', 'ledger' => 'Grand livre', 'view_pdf' => 'Voir le PDF', @@ -3496,7 +3496,7 @@ Lorsque les montant apparaîtront sur votre relevé, veuillez revenir sur cette 'selfhosted' => 'Auto-hébergé', 'hide_menu' => 'Masquer', 'show_menu' => 'Afficher', - 'partially_refunded' => 'Partiellement remboursé', + 'partially_refunded' => 'Remboursement partiel', 'search_documents' => 'Recherche de documents', 'search_designs' => 'Recherche de modèles', 'search_invoices' => 'Recherche de factures', @@ -3536,8 +3536,8 @@ Lorsque les montant apparaîtront sur votre relevé, veuillez revenir sur cette 'system_logs' => 'Journaux système', 'copy_link' => 'Copier le lien', 'welcome_to_invoice_ninja' => 'Bienvenue dans Invoice Ninja', - 'optin' => 'Adhésion', - 'optout' => 'Désadhésion', + 'optin' => 'Adhérer', + 'optout' => 'Désadhérer', 'auto_convert' => 'Conversion automatique', 'reminder1_sent' => 'Rappel 1 envoyé', 'reminder2_sent' => 'Rappel 2 envoyé', @@ -3642,7 +3642,7 @@ Lorsque les montant apparaîtront sur votre relevé, veuillez revenir sur cette 'add_documents_to_invoice_help' => 'Rendre les documents visibles pour le client', 'convert_currency_help' => 'Définir un taux d\'échange', 'expense_settings' => 'Paramètres des dépenses', - 'clone_to_recurring' => 'Cloner en récurrence', + 'clone_to_recurring' => 'Dupliquer en récurrence', 'crypto' => 'Crypto', 'user_field' => 'Champs utilisateur', 'variables' => 'Variables', @@ -3747,8 +3747,8 @@ Lorsque les montant apparaîtront sur votre relevé, veuillez revenir sur cette 'sidebar_editor' => 'Éditeur de barre latérale', 'please_type_to_confirm' => 'Veuillez saisir ":value" pour confirmer', 'purge' => 'Purger', - 'clone_to' => 'Cloner vers', - 'clone_to_other' => 'Cloner vers Autre', + 'clone_to' => 'Dupliquer en', + 'clone_to_other' => 'Dupliquer en Autre', 'labels' => 'Étiquettes', 'add_custom' => 'Ajout personnalisé', 'payment_tax' => 'Paiement de taxe', @@ -3815,7 +3815,7 @@ Lorsque les montant apparaîtront sur votre relevé, veuillez revenir sur cette 'no_file_selected' => 'Aucun fichier sélectionné', 'import_type' => 'Type d\'importation', 'draft_mode' => 'Mode brouillon', - 'draft_mode_help' => 'Prévisualisations mises à jour plus rapidement mais moins précises', + 'draft_mode_help' => 'Prévisualisation plus rapide, mais moins précise', 'show_product_discount' => 'Afficher le rabais de produit', 'show_product_discount_help' => 'Afficher un champ rabais de ligne d\'article', 'tax_name3' => 'Nom de taxe 3', @@ -3830,7 +3830,7 @@ Lorsque les montant apparaîtront sur votre relevé, veuillez revenir sur cette 'save_and_preview' => 'Enregistrer et prévisualiser', 'save_and_email' => 'Enregistrer et envoyer par courriel', 'converted_balance' => 'Solde converti', - 'is_sent' => 'Est Envoyé', + 'is_sent' => 'Est envoyé', 'document_upload' => 'Téléversement de document', 'document_upload_help' => 'Autoriser les clients à téléverser des documents', 'expense_total' => 'Total des dépenses', @@ -4335,7 +4335,7 @@ Lorsque les montant apparaîtront sur votre relevé, veuillez revenir sur cette 'expense_tax_help' => 'Les taxes par article sont désactivées', 'enable_markdown' => 'Activer Markdown', 'enable_markdown_help' => 'Convertir Markdown en HTML dans le PDF', - 'add_second_contact' => 'Ajouter un 2e contact', + 'add_second_contact' => 'Ajouter un dexième contact', 'previous_page' => 'Page précédente', 'next_page' => 'Page suivante', 'export_colors' => 'Exporter les couleurs', @@ -4360,7 +4360,7 @@ Lorsque les montant apparaîtront sur votre relevé, veuillez revenir sur cette 'change_email' => 'Modifier l\'adresse courriel', 'client_portal_domain_hint' => 'Paramétrez de façon optionnelle, un domaine séparé pour le portail du client', 'tasks_shown_in_portal' => 'Tâches affichées dans le portail', - 'uninvoiced' => 'Défacturé', + 'uninvoiced' => 'Non facturé', 'subdomain_guide' => 'Le sous-domaine est utilisé dans le portail du client pour personnaliser les liens à votre marque. Ex. https://votremarque.invoicing.co', 'send_time' => 'Heure d\'envoi', 'import_settings' => 'Importer les paramètres', @@ -4685,7 +4685,7 @@ Lorsque les montant apparaîtront sur votre relevé, veuillez revenir sur cette 'fields_per_row' => 'Champs par ligne', 'total_active_invoices' => 'Factures en cours', 'total_outstanding_invoices' => 'Factures impayées', - 'total_completed_payments' => 'Paiements reçus', + 'total_completed_payments' => 'Paiements complétés', 'total_refunded_payments' => 'Paiements remboursés', 'total_active_quotes' => 'Soumissions en cours', 'total_approved_quotes' => 'Soumissions approuvées', @@ -4942,7 +4942,7 @@ Lorsque les montant apparaîtront sur votre relevé, veuillez revenir sur cette 'no_documents_to_download' => 'Aucun document disponible en téléchargement pour les enregistrements sélectionnés', 'pixels' => 'Pixels', 'logo_size' => 'Taille du logo', - 'failed' => 'Échec', + 'failed' => 'Échoué', 'client_contacts' => 'Personne contact du client', 'sync_from' => 'Sync de', 'gateway_payment_text' => 'Factures: :invoices pour :amount pour :client', @@ -5132,7 +5132,7 @@ Lorsque les montant apparaîtront sur votre relevé, veuillez revenir sur cette 'default_payment_type' => 'Type de paiement par défaut', 'number_precision' => 'Précision du nombre', 'number_precision_help' => 'Contrôle le nombre de décimales supportées dans l\'interface', - 'is_tax_exempt' => 'Exonéré de taxe', + 'is_tax_exempt' => 'Exemption de taxes', 'drop_files_here' => 'Déposez les fichiers ici', 'upload_files' => 'Téléverser les fichiers', 'download_e_invoice' => 'Télécharger la facture électronique', @@ -5150,6 +5150,9 @@ Lorsque les montant apparaîtront sur votre relevé, veuillez revenir sur cette 'unlinked_transaction' => 'La transactions a été déliée', 'view_dashboard_permission' => 'Autoriser l\'accès de l\'utilisateur au tableau de bord. Les données sont limitées aux permissions disponibles.', 'marked_sent_credits' => 'Les crédits envoyés ont été marqués', + 'show_document_preview' => 'Afficher la visualisation de document', + 'cash_accounting' => 'Comptabilité de caisse', + 'click_or_drop_files_here' => 'Cliquez ou déposez les fichiers ici', ); return $LANG; From e2542e33bdfa1323cb8381e093b6939081b2d1b5 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Mon, 11 Sep 2023 10:13:13 +1000 Subject: [PATCH 02/20] Refactor for public/private documents --- app/Mail/Engine/CreditEmailEngine.php | 8 ++++---- app/Mail/Engine/InvoiceEmailEngine.php | 20 ++++++++++---------- app/Mail/Engine/PaymentEmailEngine.php | 4 ++-- app/Mail/Engine/PurchaseOrderEmailEngine.php | 8 ++++---- app/Mail/Engine/QuoteEmailEngine.php | 8 ++++---- app/Services/Email/EmailDefaults.php | 4 ++-- lang/en/texts.php | 7 ++----- 7 files changed, 28 insertions(+), 31 deletions(-) diff --git a/app/Mail/Engine/CreditEmailEngine.php b/app/Mail/Engine/CreditEmailEngine.php index 6e2191b6594c..d6a7bda08b15 100644 --- a/app/Mail/Engine/CreditEmailEngine.php +++ b/app/Mail/Engine/CreditEmailEngine.php @@ -123,21 +123,21 @@ class CreditEmailEngine extends BaseEmailEngine //attach third party documents if ($this->client->getSetting('document_email_attachment') !== false && $this->credit->company->account->hasFeature(Account::FEATURE_DOCUMENTS)) { // Storage::url - foreach ($this->credit->documents as $document) { + $this->credit->documents()->where('is_public',true)->cursor()->each(function($document) { if ($document->size > $this->max_attachment_size) { $this->setAttachmentLinks([" $document->hash]) ."'>". $document->name .""]); } else { $this->setAttachments([['path' => $document->filePath(), 'name' => $document->name, 'mime' => null, 'file' => base64_encode($document->getFile())]]); } - } + }); - foreach ($this->credit->company->documents as $document) { + $this->credit->company->documents()->where('is_public',true)->cursor()->each(function($document) { if ($document->size > $this->max_attachment_size) { $this->setAttachmentLinks([" $document->hash]) ."'>". $document->name .""]); } else { $this->setAttachments([['path' => $document->filePath(), 'name' => $document->name, 'mime' => null, 'file' => base64_encode($document->getFile())]]); } - } + }); } return $this; diff --git a/app/Mail/Engine/InvoiceEmailEngine.php b/app/Mail/Engine/InvoiceEmailEngine.php index 79826b3a0345..70ab7ee7060f 100644 --- a/app/Mail/Engine/InvoiceEmailEngine.php +++ b/app/Mail/Engine/InvoiceEmailEngine.php @@ -135,31 +135,31 @@ class InvoiceEmailEngine extends BaseEmailEngine //attach third party documents if ($this->client->getSetting('document_email_attachment') !== false && $this->invoice->company->account->hasFeature(Account::FEATURE_DOCUMENTS)) { if ($this->invoice->recurring_invoice()->exists()) { - foreach ($this->invoice->recurring_invoice->documents as $document) { + $this->invoice->recurring_invoice->documents()->where('is_public',true)->cursor()->each(function ($document) { if ($document->size > $this->max_attachment_size) { $this->setAttachmentLinks([" $document->hash]) ."'>". $document->name .""]); } else { $this->setAttachments([['file' => base64_encode($document->getFile()), 'path' => $document->filePath(), 'name' => $document->name, 'mime' => null, ]]); } - } + }); } // Storage::url - foreach ($this->invoice->documents as $document) { + $this->invoice->documents()->where('is_public',true)->cursor()->each(function ($document) { if ($document->size > $this->max_attachment_size) { $this->setAttachmentLinks([" $document->hash]) ."'>". $document->name .""]); } else { $this->setAttachments([['file' => base64_encode($document->getFile()), 'path' => $document->filePath(), 'name' => $document->name, 'mime' => null, ]]); } - } + }); - foreach ($this->invoice->company->documents as $document) { + $this->invoice->company->documents()->where('is_public',true)->cursor()->each(function ($document) { if ($document->size > $this->max_attachment_size) { $this->setAttachmentLinks([" $document->hash]) ."'>". $document->name .""]); } else { $this->setAttachments([['file' => base64_encode($document->getFile()), 'path' => $document->filePath(), 'name' => $document->name, 'mime' => null, ]]); } - } + }); $line_items = $this->invoice->line_items; @@ -175,13 +175,13 @@ class InvoiceEmailEngine extends BaseEmailEngine ->where('invoice_documents', 1) ->cursor() ->each(function ($expense) { - foreach ($expense->documents as $document) { + $expense->documents()->where('is_public',true)->cursor()->each(function ($document) { if ($document->size > $this->max_attachment_size) { $this->setAttachmentLinks([" $document->hash]) ."'>". $document->name .""]); } else { $this->setAttachments([['path' => $document->filePath(), 'name' => $document->name, 'mime' => null, ]]); } - } + }); }); } @@ -195,13 +195,13 @@ class InvoiceEmailEngine extends BaseEmailEngine $tasks = Task::query()->whereIn('id', $this->transformKeys($task_ids)) ->cursor() ->each(function ($task) { - foreach ($task->documents as $document) { + $task->documents()->where('is_public', true)->cursor()->each(function ($document) { if ($document->size > $this->max_attachment_size) { $this->setAttachmentLinks([" $document->hash]) ."'>". $document->name .""]); } else { $this->setAttachments([['path' => $document->filePath(), 'name' => $document->name, 'mime' => null, ]]); } - } + }); }); } } diff --git a/app/Mail/Engine/PaymentEmailEngine.php b/app/Mail/Engine/PaymentEmailEngine.php index 0e890e2165e7..400bef9b0618 100644 --- a/app/Mail/Engine/PaymentEmailEngine.php +++ b/app/Mail/Engine/PaymentEmailEngine.php @@ -98,13 +98,13 @@ class PaymentEmailEngine extends BaseEmailEngine //attach invoice documents also to payments if ($this->client->getSetting('document_email_attachment') !== false) { - foreach ($invoice->documents as $document) { + $invoice->documents()->where('is_public', true)->cursor()->each(function ($document){ if ($document->size > $this->max_attachment_size) { $this->setAttachmentLinks([" $document->hash]) ."'>". $document->name .""]); } else { $this->setAttachments([['path' => $document->filePath(), 'name' => $document->name, 'mime' => null, ]]); } - } + }); } if($this->client->getSetting('enable_e_invoice')) diff --git a/app/Mail/Engine/PurchaseOrderEmailEngine.php b/app/Mail/Engine/PurchaseOrderEmailEngine.php index 4bdd16f17e4a..51f6d5bd5360 100644 --- a/app/Mail/Engine/PurchaseOrderEmailEngine.php +++ b/app/Mail/Engine/PurchaseOrderEmailEngine.php @@ -127,21 +127,21 @@ class PurchaseOrderEmailEngine extends BaseEmailEngine //attach third party documents if ($this->vendor->getSetting('document_email_attachment') !== false && $this->purchase_order->company->account->hasFeature(Account::FEATURE_DOCUMENTS)) { // Storage::url - foreach ($this->purchase_order->documents as $document) { + $this->purchase_order->documents()->where('is_public', true)->cursor()->each(function ($document) { if ($document->size > $this->max_attachment_size) { $this->setAttachmentLinks([" $document->hash]) ."'>". $document->name .""]); } else { $this->setAttachments([['path' => $document->filePath(), 'name' => $document->name, 'mime' => null]]); } - } + }); - foreach ($this->purchase_order->company->documents as $document) { + $this->purchase_order->company->documents()->where('is_public', true)->cursor()->each(function ($document) { if ($document->size > $this->max_attachment_size) { $this->setAttachmentLinks([" $document->hash]) ."'>". $document->name .""]); } else { $this->setAttachments([['path' => $document->filePath(), 'name' => $document->name, 'mime' => null]]); } - } + }); } return $this; diff --git a/app/Mail/Engine/QuoteEmailEngine.php b/app/Mail/Engine/QuoteEmailEngine.php index 8e36291b0d42..72f3a13db1d7 100644 --- a/app/Mail/Engine/QuoteEmailEngine.php +++ b/app/Mail/Engine/QuoteEmailEngine.php @@ -121,21 +121,21 @@ class QuoteEmailEngine extends BaseEmailEngine //attach third party documents if ($this->client->getSetting('document_email_attachment') !== false && $this->quote->company->account->hasFeature(Account::FEATURE_DOCUMENTS)) { // Storage::url - foreach ($this->quote->documents as $document) { + $this->quote->documents()->where('is_public', true)->cursor()->each(function ($document) { if ($document->size > $this->max_attachment_size) { $this->setAttachmentLinks([" $document->hash]) ."'>". $document->name .""]); } else { $this->setAttachments([['file' => base64_encode($document->getFile()), 'path' => $document->filePath(), 'name' => $document->name, 'mime' => null, ]]); } - } + }); - foreach ($this->quote->company->documents as $document) { + $this->quote->company->documents()->where('is_public', true)->cursor()->each(function ($document) { if ($document->size > $this->max_attachment_size) { $this->setAttachmentLinks([" $document->hash]) ."'>". $document->name .""]); } else { $this->setAttachments([['file' => base64_encode($document->getFile()), 'path' => $document->filePath(), 'name' => $document->name, 'mime' => null, ]]); } - } + }); } return $this; diff --git a/app/Services/Email/EmailDefaults.php b/app/Services/Email/EmailDefaults.php index e2d833fa9e31..4e87b63a174b 100644 --- a/app/Services/Email/EmailDefaults.php +++ b/app/Services/Email/EmailDefaults.php @@ -365,7 +365,7 @@ class EmailDefaults ->where('invoice_documents', 1) ->cursor() ->each(function ($expense) { - $this->email->email_object->documents = array_merge($this->email->email_object->documents, $expense->documents->pluck('id')->toArray()); + $this->email->email_object->documents = array_merge($this->email->email_object->documents, $expense->documents()->where('is_public',true)->pluck('id')->toArray()); }); } @@ -373,7 +373,7 @@ class EmailDefaults Task::query()->whereIn('id', $this->transformKeys($task_ids)) ->cursor() ->each(function ($task) { - $this->email->email_object->documents = array_merge($this->email->email_object->documents, $task->documents->pluck('id')->toArray()); + $this->email->email_object->documents = array_merge($this->email->email_object->documents, $task->documents()->where('is_public',true)->pluck('id')->toArray()); }); } } diff --git a/lang/en/texts.php b/lang/en/texts.php index a5bc8f47feda..f957a2bfa232 100644 --- a/lang/en/texts.php +++ b/lang/en/texts.php @@ -657,8 +657,6 @@ $LANG = array( 'created_by_invoice' => 'Created by :invoice', 'primary_user' => 'Primary User', 'help' => 'Help', - 'customize_help' => '

We use :pdfmake_link to define the invoice designs declaratively. The pdfmake :playground_link provides a great way to see the library in action.

-

If you need help figuring something out post a question to our :forum_link with the design you\'re using.

', 'playground' => 'playground', 'support_forum' => 'Support Forums', 'invoice_due_date' => 'Due Date', @@ -1822,7 +1820,6 @@ $LANG = array( 'bot_emailed_notify_paid' => 'I\'ll email you when it\'s paid.', 'add_product_to_invoice' => 'Add 1 :product', 'not_authorized' => 'You are not authorized', - 'bot_get_email' => 'Hi! (wave)
Thanks for trying the Invoice Ninja Bot.
You need to create a free account to use this bot.
Send me your account email address to get started.', 'bot_get_code' => 'Thanks! I\'ve sent a you an email with your security code.', 'bot_welcome' => 'That\'s it, your account is verified.
', 'email_not_found' => 'I wasn\'t able to find an available account for :email', @@ -1830,7 +1827,6 @@ $LANG = array( 'security_code_email_subject' => 'Security code for Invoice Ninja Bot', 'security_code_email_line1' => 'This is your Invoice Ninja Bot security code.', 'security_code_email_line2' => 'Note: it will expire in 10 minutes.', - 'bot_help_message' => 'I currently support:
• Create\update\email an invoice
• List products
For example:
invoice bob for 2 tickets, set the due date to next thursday and the discount to 10 percent', 'list_products' => 'List Products', 'include_item_taxes_inline' => 'Include line item taxes in line total', @@ -1843,7 +1839,6 @@ $LANG = array( 'update_invoiceninja_warning' => 'Before start upgrading Invoice Ninja create a backup of your database and files!', 'update_invoiceninja_available' => 'A new version of Invoice Ninja is available.', 'update_invoiceninja_unavailable' => 'No new version of Invoice Ninja available.', - 'update_invoiceninja_instructions' => 'Please install the new version :version by clicking the Update now button below. Afterwards you\'ll be redirected to the dashboard.', 'update_invoiceninja_update_start' => 'Update now', 'update_invoiceninja_download_start' => 'Download :version', 'create_new' => 'Create New', @@ -5161,6 +5156,8 @@ $LANG = array( 'show_document_preview' => 'Show Document Preview', 'cash_accounting' => 'Cash accounting', 'click_or_drop_files_here' => 'Click or drop files here', + 'set_as_public' => 'Set as public', + 'set_as_private' => 'Set as private', ); return $LANG; From 3650d2527f896ef856c78d0ffefb5ef81df4a4e0 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Mon, 11 Sep 2023 10:30:02 +1000 Subject: [PATCH 03/20] Set public/private documents --- app/Services/Email/EmailDefaults.php | 6 +++--- lang/en/texts.php | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/app/Services/Email/EmailDefaults.php b/app/Services/Email/EmailDefaults.php index 4e87b63a174b..401060b6c7b4 100644 --- a/app/Services/Email/EmailDefaults.php +++ b/app/Services/Email/EmailDefaults.php @@ -333,16 +333,16 @@ class EmailDefaults } /* Company Documents */ - $this->email->email_object->documents = array_merge($this->email->email_object->documents, $this->email->company->documents->pluck('id')->toArray()); + $this->email->email_object->documents = array_merge($this->email->email_object->documents, $this->email->company->documents()->where('is_public', true)->pluck('id')->toArray()); /** Entity Documents */ if ($this->email->email_object->entity?->documents) { - $this->email->email_object->documents = array_merge($this->email->email_object->documents, $this->email->email_object->entity->documents->pluck('id')->toArray()); + $this->email->email_object->documents = array_merge($this->email->email_object->documents, $this->email->email_object->entity->documents()->where('is_public', true)->pluck('id')->toArray()); } /** Recurring Invoice Documents */ if ($this->email->email_object->entity instanceof Invoice && $this->email->email_object->entity->recurring_id != null) { - $this->email->email_object->documents = array_merge($this->email->email_object->documents, $this->email->email_object->entity->recurring_invoice->documents->pluck('id')->toArray()); + $this->email->email_object->documents = array_merge($this->email->email_object->documents, $this->email->email_object->entity->recurring_invoice->documents()->where('is_public', true)->pluck('id')->toArray()); } /** Task / Expense Documents */ diff --git a/lang/en/texts.php b/lang/en/texts.php index f957a2bfa232..8be95187c7be 100644 --- a/lang/en/texts.php +++ b/lang/en/texts.php @@ -5156,8 +5156,8 @@ $LANG = array( 'show_document_preview' => 'Show Document Preview', 'cash_accounting' => 'Cash accounting', 'click_or_drop_files_here' => 'Click or drop files here', - 'set_as_public' => 'Set as public', - 'set_as_private' => 'Set as private', + 'set_public' => 'Set public', + 'set_private' => 'Set private', ); return $LANG; From 7128bd434b576673219e446be918e55666e37c97 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Mon, 11 Sep 2023 20:33:56 +1000 Subject: [PATCH 04/20] Working on report previews --- app/Export/CSV/BaseExport.php | 32 ++++++++++++++ app/Export/CSV/ClientExport.php | 42 +++++++++++++++---- app/Export/CSV/ContactExport.php | 3 +- app/Export/CSV/CreditExport.php | 2 +- app/Export/CSV/DocumentExport.php | 22 ++++++++++ app/Export/CSV/ExpenseExport.php | 3 +- app/Export/CSV/InvoiceExport.php | 3 +- app/Export/CSV/InvoiceItemExport.php | 7 ---- .../Reports/DocumentReportController.php | 24 ++++++++--- 9 files changed, 114 insertions(+), 24 deletions(-) diff --git a/app/Export/CSV/BaseExport.php b/app/Export/CSV/BaseExport.php index 6be20cafa90f..483c1c0b4a48 100644 --- a/app/Export/CSV/BaseExport.php +++ b/app/Export/CSV/BaseExport.php @@ -13,6 +13,7 @@ namespace App\Export\CSV; use App\Utils\Number; use App\Models\Client; +use App\Models\ClientContact; use App\Utils\Helpers; use App\Models\Company; use App\Models\Expense; @@ -1028,4 +1029,35 @@ class BaseExport return $header; } + + public function processMetaData(array $row, $resource): array + { + $class = get_class($resource); + + match ($class) { + Invoice::class => $entity = 'invoice', + Expense::class => $entity = 'expense', + ClientContact::class => $entity = 'contact', + default => $entity = 'invoice', + }; + + $clean_row = []; + + foreach (array_values($this->input['report_keys']) as $key => $value) { + + $report_keys = explode(".", $value); + + $column_key = $value; + $clean_row[$key]['entity'] = $report_keys[0]; + $clean_row[$key]['id'] = $report_keys[1] ?? $report_keys[0]; + $clean_row[$key]['hashed_id'] = $report_keys[0] == $entity ? null : $resource->{$report_keys[0]}->hashed_id ?? null; + $clean_row[$key]['value'] = $row[$column_key]; + $clean_row[$key]['identifier'] = $value; + $clean_row[$key]['display_value'] = $row[$column_key]; + + } + + return $clean_row; + } + } diff --git a/app/Export/CSV/ClientExport.php b/app/Export/CSV/ClientExport.php index 608595196fea..79a59ddbd71a 100644 --- a/app/Export/CSV/ClientExport.php +++ b/app/Export/CSV/ClientExport.php @@ -11,15 +11,16 @@ namespace App\Export\CSV; -use App\Libraries\MultiDB; -use App\Models\Client; -use App\Models\Company; -use App\Transformers\ClientContactTransformer; -use App\Transformers\ClientTransformer; use App\Utils\Ninja; -use Illuminate\Database\Eloquent\Builder; -use Illuminate\Support\Facades\App; +use App\Utils\Number; +use App\Models\Client; use League\Csv\Writer; +use App\Models\Company; +use App\Libraries\MultiDB; +use Illuminate\Support\Facades\App; +use App\Transformers\ClientTransformer; +use Illuminate\Database\Eloquent\Builder; +use App\Transformers\ClientContactTransformer; class ClientExport extends BaseExport { @@ -93,7 +94,8 @@ class ClientExport extends BaseExport $report = $query->cursor() ->map(function ($client) { - return $this->buildRow($client); + $row = $this->buildRow($client); + return $this->processMetaData($row, $client); })->toArray(); return array_merge(['columns' => $header], $report); @@ -171,6 +173,30 @@ class ClientExport extends BaseExport return $this->decorateAdvancedFields($client, $entity); } + public function processMetaData(array $row, $resource): array + { + $clean_row = []; + foreach (array_values($this->input['report_keys']) as $key => $value) { + + $report_keys = explode(".", $value); + + $column_key = $value; + $clean_row[$key]['entity'] = $report_keys[0]; + $clean_row[$key]['id'] = $report_keys[1] ?? $report_keys[0]; + $clean_row[$key]['hashed_id'] = $report_keys[0] == 'client' ? null : $resource->{$report_keys[0]}->hashed_id ?? null; + $clean_row[$key]['value'] = $row[$column_key]; + $clean_row[$key]['identifier'] = $value; + + if(in_array($clean_row[$key]['id'], ['paid_to_date', 'balance', 'credit_balance','payment_balance'])) + $clean_row[$key]['display_value'] = Number::formatMoney($row[$column_key], $resource); + else + $clean_row[$key]['display_value'] = $row[$column_key]; + + } + + return $clean_row; + } + private function decorateAdvancedFields(Client $client, array $entity) :array { if (in_array('client.user', $this->input['report_keys'])) { diff --git a/app/Export/CSV/ContactExport.php b/app/Export/CSV/ContactExport.php index 5efddeaade90..9de6b85d7420 100644 --- a/app/Export/CSV/ContactExport.php +++ b/app/Export/CSV/ContactExport.php @@ -94,7 +94,8 @@ class ContactExport extends BaseExport $report = $query->cursor() ->map(function ($contact) { - return $this->buildRow($contact); + $row = $this->buildRow($contact); + return $this->processMetaData($row, $contact); })->toArray(); return array_merge(['columns' => $header], $report); diff --git a/app/Export/CSV/CreditExport.php b/app/Export/CSV/CreditExport.php index d9641895371b..ca0fde8bfed6 100644 --- a/app/Export/CSV/CreditExport.php +++ b/app/Export/CSV/CreditExport.php @@ -56,7 +56,7 @@ class CreditExport extends BaseExport return array_merge(['columns' => $header], $report); } - private function processMetaData(array $row, Credit $credit): array + public function processMetaData(array $row, $resource): array { $clean_row = []; foreach (array_values($this->input['report_keys']) as $key => $value) { diff --git a/app/Export/CSV/DocumentExport.php b/app/Export/CSV/DocumentExport.php index 26d55840e431..391fe14050a3 100644 --- a/app/Export/CSV/DocumentExport.php +++ b/app/Export/CSV/DocumentExport.php @@ -56,11 +56,33 @@ class DocumentExport extends BaseExport $report = $query->cursor() ->map(function ($document) { $row = $this->buildRow($document); + return $this->processMetaData($row, $document); })->toArray(); return array_merge(['columns' => $header], $report); } + private function processMetaData(array $row, Document $document): array + { + $clean_row = []; + foreach (array_values($this->input['report_keys']) as $key => $value) { + + $report_keys = explode(".", $value); + + $column_key = $value; + $clean_row[$key]['entity'] = $report_keys[0]; + $clean_row[$key]['id'] = $report_keys[1] ?? $report_keys[0]; + $clean_row[$key]['hashed_id'] = $report_keys[0] == 'document' ? null : $document->{$report_keys[0]}->hashed_id ?? null; + $clean_row[$key]['value'] = $row[$column_key]; + $clean_row[$key]['identifier'] = $value; + + $clean_row[$key]['display_value'] = $row[$column_key]; + + } + + return $clean_row; + } + private function init(): Builder { diff --git a/app/Export/CSV/ExpenseExport.php b/app/Export/CSV/ExpenseExport.php index 1eb5747cc16f..32eaf9b6ca60 100644 --- a/app/Export/CSV/ExpenseExport.php +++ b/app/Export/CSV/ExpenseExport.php @@ -49,7 +49,8 @@ class ExpenseExport extends BaseExport $report = $query->cursor() ->map(function ($resource) { - return $this->buildRow($resource); + $row = $this->buildRow($resource); + return $this->processMetaData($row, $resource); })->toArray(); return array_merge(['columns' => $header], $report); diff --git a/app/Export/CSV/InvoiceExport.php b/app/Export/CSV/InvoiceExport.php index bf999f9177f7..4123940a7695 100644 --- a/app/Export/CSV/InvoiceExport.php +++ b/app/Export/CSV/InvoiceExport.php @@ -78,7 +78,8 @@ class InvoiceExport extends BaseExport $report = $query->cursor() ->map(function ($resource) { - return $this->buildRow($resource); + $row = $this->buildRow($resource); + return $this->processMetaData($row, $resource); })->toArray(); return array_merge(['columns' => $header], $report); diff --git a/app/Export/CSV/InvoiceItemExport.php b/app/Export/CSV/InvoiceItemExport.php index d7db46889269..a721efe97be2 100644 --- a/app/Export/CSV/InvoiceItemExport.php +++ b/app/Export/CSV/InvoiceItemExport.php @@ -188,13 +188,6 @@ class InvoiceItemExport extends BaseExport $entity['tax_category'] = $invoice->taxTypeString($entity['tax_category']); } - // if($this->force_keys) { - // $entity['client'] = $invoice->client->present()->name(); - // $entity['client_id_number'] = $invoice->client->id_number; - // $entity['client_number'] = $invoice->client->number; - // $entity['status'] = $invoice->stringStatus($invoice->status_id); - // } - return $entity; } } diff --git a/app/Http/Controllers/Reports/DocumentReportController.php b/app/Http/Controllers/Reports/DocumentReportController.php index 42dc7478c962..d0cd939c86a7 100644 --- a/app/Http/Controllers/Reports/DocumentReportController.php +++ b/app/Http/Controllers/Reports/DocumentReportController.php @@ -11,12 +11,13 @@ namespace App\Http\Controllers\Reports; +use Illuminate\Http\Response; +use App\Utils\Traits\MakesHash; +use App\Jobs\Report\SendToAdmin; use App\Export\CSV\DocumentExport; +use App\Jobs\Report\PreviewReport; use App\Http\Controllers\BaseController; use App\Http\Requests\Report\GenericReportRequest; -use App\Jobs\Report\SendToAdmin; -use App\Utils\Traits\MakesHash; -use Illuminate\Http\Response; class DocumentReportController extends BaseController { @@ -62,14 +63,27 @@ class DocumentReportController extends BaseController */ public function __invoke(GenericReportRequest $request) { + + /** @var \App\Models\User $user */ + $user = auth()->user(); + if ($request->has('send_email') && $request->get('send_email')) { - SendToAdmin::dispatch(auth()->user()->company(), $request->all(), DocumentExport::class, $this->filename); + SendToAdmin::dispatch($user->company(), $request->all(), DocumentExport::class, $this->filename); return response()->json(['message' => 'working...'], 200); } // expect a list of visible fields, or use the default - $export = new DocumentExport(auth()->user()->company(), $request->all()); + if($request->has('output') && $request->input('output') == 'json') { + + $hash = \Illuminate\Support\Str::uuid(); + + PreviewReport::dispatch($user->company(), $request->all(), DocumentExport::class, $hash); + + return response()->json(['message' => $hash], 200); + } + + $export = new DocumentExport($user->company(), $request->all()); $csv = $export->run(); From 7566d277cee4bfb67f77810f09849c66fa432db0 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Mon, 11 Sep 2023 22:15:24 +1000 Subject: [PATCH 05/20] Fixes for invoice items --- app/Export/CSV/InvoiceItemExport.php | 42 +++++++++++++++++++++++++--- 1 file changed, 38 insertions(+), 4 deletions(-) diff --git a/app/Export/CSV/InvoiceItemExport.php b/app/Export/CSV/InvoiceItemExport.php index a721efe97be2..92e85fcd348a 100644 --- a/app/Export/CSV/InvoiceItemExport.php +++ b/app/Export/CSV/InvoiceItemExport.php @@ -81,12 +81,16 @@ class InvoiceItemExport extends BaseExport return ['identifier' => $value, 'display_value' => $headerdisplay[$value]]; })->toArray(); - $query->cursor() - ->each(function ($resource) { + $items = $query->cursor() + ->map(function ($resource) { $this->iterateItems($resource); - }); + $row = $this->processMetaData($this->storage_array[0], $resource); + $this->storage_array = []; + return $row; + })->toArray(); - return array_merge(['columns' => $header], $this->storage_array); + + return array_merge(['columns' => $header], $items); } @@ -190,4 +194,34 @@ class InvoiceItemExport extends BaseExport return $entity; } + + public function processMetaData(array $row, $resource): array + { + $entity = 'invoice'; + $clean_row = []; + + foreach (array_values($this->input['report_keys']) as $key => $value) { + + $report_keys = explode(".", $value); + + $column_key = $value; + + if($value == 'type_id' || $value == 'item.type_id') + $column_key = 'type'; + + if($value == 'tax_id' || $value == 'item.tax_id') + $column_key = 'tax_category'; + + $clean_row[$key]['entity'] = $report_keys[0]; + $clean_row[$key]['id'] = $report_keys[1] ?? $report_keys[0]; + $clean_row[$key]['hashed_id'] = $report_keys[0] == $entity ? null : $resource->{$report_keys[0]}->hashed_id ?? null; + $clean_row[$key]['value'] = isset($row[$column_key]) ? $row[$column_key] : $row[$report_keys[1]]; + $clean_row[$key]['identifier'] = $value; + $clean_row[$key]['display_value'] = isset($row[$column_key]) ? $row[$column_key] : $row[$report_keys[1]]; + + } + + return $clean_row; + } + } From 042374463e12a81411edea6eec9b47ed5616e0d4 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Tue, 12 Sep 2023 07:29:00 +1000 Subject: [PATCH 06/20] Updates for quote to project conversion --- app/Http/Controllers/QuoteController.php | 11 +++-------- app/Services/Quote/ConvertQuoteToProject.php | 2 +- 2 files changed, 4 insertions(+), 9 deletions(-) diff --git a/app/Http/Controllers/QuoteController.php b/app/Http/Controllers/QuoteController.php index 301307372ae6..45cfc2293fd8 100644 --- a/app/Http/Controllers/QuoteController.php +++ b/app/Http/Controllers/QuoteController.php @@ -576,14 +576,9 @@ class QuoteController extends BaseController if ($action == 'convert_to_project') { $quotes->each(function ($quote, $key) use ($user) { if ($user->can('edit', $quote)) { - $project = CloneQuoteToProjectFactory::create($quote, $user->id); - - if (empty($project->number)) { - $project->number = $this->getNextProjectNumber($project); - } - $project->save(); - $quote->project_id = $project->id; - $quote->save(); + + $quote->service()->convertToProject(); + } }); diff --git a/app/Services/Quote/ConvertQuoteToProject.php b/app/Services/Quote/ConvertQuoteToProject.php index d74b05f49ebd..6b1b642cd16a 100644 --- a/app/Services/Quote/ConvertQuoteToProject.php +++ b/app/Services/Quote/ConvertQuoteToProject.php @@ -64,7 +64,7 @@ class ConvertQuoteToProject $task->project_id = $this->quote->project_id; $task->description = $item->notes; $task->status_id = $task_status->id; - $task->rate = $item->unit_cost; + $task->rate = $item->cost; $task_repo->save([], $task); }); From a0a6054faa58c528b5abb9461b6b6a173b81e166 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Tue, 12 Sep 2023 10:27:30 +1000 Subject: [PATCH 07/20] Fixes for Checkout v3 --- app/PaymentDrivers/CheckoutCom/CreditCard.php | 100 +++---- app/PaymentDrivers/CheckoutCom/Utilities.php | 12 +- .../CheckoutComPaymentDriver.php | 173 +++++++------ app/Services/Payment/RefundPayment.php | 2 +- composer.lock | 245 +++++++++--------- 5 files changed, 261 insertions(+), 271 deletions(-) diff --git a/app/PaymentDrivers/CheckoutCom/CreditCard.php b/app/PaymentDrivers/CheckoutCom/CreditCard.php index 116123e16796..8a0166eb0cdb 100644 --- a/app/PaymentDrivers/CheckoutCom/CreditCard.php +++ b/app/PaymentDrivers/CheckoutCom/CreditCard.php @@ -12,25 +12,25 @@ namespace App\PaymentDrivers\CheckoutCom; -use App\Exceptions\PaymentFailed; -use App\Http\Requests\ClientPortal\Payments\PaymentResponseRequest; -use App\Jobs\Util\SystemLogger; -use App\Models\ClientGatewayToken; -use App\Models\GatewayType; use App\Models\SystemLog; -use App\PaymentDrivers\CheckoutComPaymentDriver; -use App\PaymentDrivers\Common\MethodInterface; +use Illuminate\View\View; +use App\Models\GatewayType; +use Illuminate\Http\Request; +use App\Jobs\Util\SystemLogger; use App\Utils\Traits\MakesHash; +use App\Exceptions\PaymentFailed; +use App\Models\ClientGatewayToken; use Checkout\CheckoutApiException; +use Illuminate\Contracts\View\Factory; use Checkout\CheckoutArgumentException; use Checkout\CheckoutAuthorizationException; -use Checkout\Payments\Four\Request\PaymentRequest; -use Checkout\Payments\Four\Request\Source\RequestTokenSource; -use Checkout\Payments\PaymentRequest as PaymentsPaymentRequest; -use Checkout\Payments\Source\RequestTokenSource as SourceRequestTokenSource; -use Illuminate\Contracts\View\Factory; -use Illuminate\Http\Request; -use Illuminate\View\View; +use Checkout\Payments\Request\PaymentRequest; +use App\PaymentDrivers\Common\MethodInterface; +use App\PaymentDrivers\CheckoutComPaymentDriver; +use Checkout\Payments\Previous\Source\RequestTokenSource; +use App\Http\Requests\ClientPortal\Payments\PaymentResponseRequest; +use Checkout\Payments\Previous\PaymentRequest as PreviousPaymentRequest; +use Checkout\Payments\Request\Source\RequestTokenSource as SourceRequestTokenSource; class CreditCard implements MethodInterface { @@ -67,12 +67,12 @@ class CreditCard implements MethodInterface if ($this->checkout->is_four_api) { $token_source = new RequestTokenSource(); $token_source->token = $token; - $request = new PaymentRequest(); + $request = new PreviousPaymentRequest(); $request->source = $token_source; } else { $token_source = new SourceRequestTokenSource(); $token_source->token = $token; - $request = new PaymentsPaymentRequest(); + $request = new PaymentRequest(); $request->source = $token_source; } @@ -120,44 +120,24 @@ class CreditCard implements MethodInterface return redirect()->route('client.payment_methods.show', $payment_method->hashed_id); } } catch (CheckoutApiException $e) { - // API error - $request_id = $e->request_id ?: ''; - $http_status_code = $e->http_status_code ?: ''; + $error_details = $e->error_details; - if (is_array($error_details)) { + if (isset($e->error_details['error_codes']) ?? false) { $error_details = end($e->error_details['error_codes']); } + else { + $error_details = $e->getMessage(); + } - $human_exception = $error_details ? $error_details : $e->getMessage(); - - $human_exception = "{$human_exception} - Request ID: {$request_id}"; - - throw new PaymentFailed($human_exception, $http_status_code); + throw new PaymentFailed($error_details, $e->getCode()); } catch (CheckoutArgumentException $e) { // Bad arguments - - $error_details = $e->error_details; - - if (is_array($error_details)) { - $error_details = end($e->error_details['error_codes']); - } - - $human_exception = $error_details ? $error_details : $e->getMessage(); - - throw new PaymentFailed($human_exception, 422); + throw new PaymentFailed($e->getMessage(), $e->getCode()); } catch (CheckoutAuthorizationException $e) { // Bad Invalid authorization - - $error_details = $e->error_details; - - if (is_array($error_details)) { - $error_details = end($e->error_details['error_codes']); - } - $human_exception = $error_details ? $error_details : $e->getMessage(); - - throw new PaymentFailed($human_exception, 401); + throw new PaymentFailed("There is a problem with your Checkout Gateway API keys", 401); } } @@ -280,8 +260,6 @@ class CreditCard implements MethodInterface } } catch (CheckoutApiException $e) { // API error - $request_id = $e->request_id; - $http_status_code = $e->http_status_code; $error_details = $e->error_details; if (is_array($error_details)) { @@ -293,7 +271,7 @@ class CreditCard implements MethodInterface $human_exception = $error_details ? new \Exception($error_details, 400) : $e; SystemLogger::dispatch( - $human_exception->getMessage(), + $e->getMessage(), SystemLog::CATEGORY_GATEWAY_RESPONSE, SystemLog::EVENT_GATEWAY_ERROR, SystemLog::TYPE_CHECKOUT, @@ -304,19 +282,11 @@ class CreditCard implements MethodInterface return $this->checkout->processInternallyFailedPayment($this->checkout, $human_exception); } catch (CheckoutArgumentException $e) { // Bad arguments - - $error_details = $e->error_details; - - if (is_array($error_details)) { - $error_details = end($e->error_details['error_codes']); - } $this->checkout->unWindGatewayFees($this->checkout->payment_hash); - $human_exception = $error_details ? new \Exception($error_details, 400) : $e; - SystemLogger::dispatch( - $human_exception->getMessage(), + $e->getMessage(), SystemLog::CATEGORY_GATEWAY_RESPONSE, SystemLog::EVENT_GATEWAY_ERROR, SystemLog::TYPE_CHECKOUT, @@ -324,23 +294,15 @@ class CreditCard implements MethodInterface $this->checkout->client->company, ); - return $this->checkout->processInternallyFailedPayment($this->checkout, $human_exception); + return new PaymentFailed($e->getMessage(), $e->getCode()); + // return $this->checkout->processInternallyFailedPayment($this->checkout, $human_exception); } catch (CheckoutAuthorizationException $e) { // Bad Invalid authorization - $error_details = $e->error_details; - - if (is_array($error_details)) { - $error_details = end($e->error_details['error_codes']); - } - $this->checkout->unWindGatewayFees($this->checkout->payment_hash); - $human_exception = $error_details ? new \Exception($error_details, 400) : $e; - - SystemLogger::dispatch( - $human_exception->getMessage(), + $e->getMessage(), SystemLog::CATEGORY_GATEWAY_RESPONSE, SystemLog::EVENT_GATEWAY_ERROR, SystemLog::TYPE_CHECKOUT, @@ -348,7 +310,9 @@ class CreditCard implements MethodInterface $this->checkout->client->company, ); - return $this->checkout->processInternallyFailedPayment($this->checkout, $human_exception); + return new PaymentFailed("There was a problem communicating with the API credentials for Checkout", $e->getCode()); + + // return $this->checkout->processInternallyFailedPayment($this->checkout, $human_exception); } } } diff --git a/app/PaymentDrivers/CheckoutCom/Utilities.php b/app/PaymentDrivers/CheckoutCom/Utilities.php index ef37688c305a..860240e0a596 100644 --- a/app/PaymentDrivers/CheckoutCom/Utilities.php +++ b/app/PaymentDrivers/CheckoutCom/Utilities.php @@ -94,6 +94,16 @@ trait Utilities $error_message = 'Error processing payment.'; } + if(isset($_payment['actions'][0]['response_summary']) ?? false) { + $error_message = $_payment['actions'][0]['response_summary']; + } + + if(isset($_payment['actions'][0]['response_code']) ?? false) { + $error_code = $_payment['actions'][0]['response_code']; + } + else + $error_code = 400; + $this->getParent()->sendFailureMail($error_message); $message = [ @@ -111,7 +121,7 @@ trait Utilities ); if ($throw_exception) { - throw new PaymentFailed($error_message, 500); + throw new PaymentFailed($error_message, $error_code); } } diff --git a/app/PaymentDrivers/CheckoutComPaymentDriver.php b/app/PaymentDrivers/CheckoutComPaymentDriver.php index bfeee03569d9..a4ca85e95032 100644 --- a/app/PaymentDrivers/CheckoutComPaymentDriver.php +++ b/app/PaymentDrivers/CheckoutComPaymentDriver.php @@ -25,29 +25,28 @@ use App\Models\Payment; use App\Models\PaymentHash; use App\Models\PaymentType; use App\Models\SystemLog; +use App\PaymentDrivers\CheckoutCom\CheckoutWebhook; use App\PaymentDrivers\CheckoutCom\CreditCard; use App\PaymentDrivers\CheckoutCom\Utilities; -use App\PaymentDrivers\CheckoutCom\CheckoutWebhook; use App\Utils\Traits\SystemLogTrait; -use Checkout\CheckoutApi; use Checkout\CheckoutApiException; use Checkout\CheckoutArgumentException; use Checkout\CheckoutAuthorizationException; -use Checkout\CheckoutDefaultSdk; -use Checkout\CheckoutFourSdk; +use Checkout\CheckoutSdk; use Checkout\Common\Phone; use Checkout\Customers\CustomerRequest; -use Checkout\Customers\Four\CustomerRequest as FourCustomerRequest; use Checkout\Environment; -use Checkout\Models\Payments\Refund; -use Checkout\Payments\Four\Request\PaymentRequest; -use Checkout\Payments\Four\Request\Source\RequestIdSource as SourceRequestIdSource; -use Checkout\Payments\PaymentRequest as PaymentsPaymentRequest; +use Checkout\Payments\Previous\PaymentRequest as PreviousPaymentRequest; +use Checkout\Payments\Previous\Source\RequestIdSource as SourceRequestIdSource; use Checkout\Payments\RefundRequest; -use Checkout\Payments\Source\RequestIdSource; +use Checkout\Payments\Request\PaymentRequest; +use Checkout\Payments\Request\Source\RequestIdSource; use Exception; use Illuminate\Support\Facades\Auth; +//use Checkout\Customers\Four\CustomerRequest as FourCustomerRequest; +//use Checkout\Payments\Four\Request\Source\RequestIdSource as SourceRequestIdSource; + class CheckoutComPaymentDriver extends BaseDriver { use SystemLogTrait, Utilities; @@ -70,7 +69,7 @@ class CheckoutComPaymentDriver extends BaseDriver public $is_four_api = false; /** - * @var CheckoutApi; + * @var CheckoutSdk; */ public $gateway; @@ -117,45 +116,61 @@ class CheckoutComPaymentDriver extends BaseDriver */ public function init() { - $config = [ - 'secret' => $this->company_gateway->getConfigField('secretApiKey'), - 'public' => $this->company_gateway->getConfigField('publicApiKey'), - 'sandbox' => $this->company_gateway->getConfigField('testMode'), - ]; - if (strlen($config['secret']) <= 38) { - $this->is_four_api = true; - $builder = CheckoutFourSdk::staticKeys(); - $builder->setPublicKey($config['public']); // optional, only required for operations related with tokens - $builder->setSecretKey($config['secret']); - $builder->setEnvironment($config['sandbox'] ? Environment::sandbox() : Environment::production()); + if (str_contains($this->company_gateway->getConfigField('secretApiKey'), '-')) { + + $this->is_four_api = true; //was four api, now known as previous. + + $builder = CheckoutSdk::builder() + ->previous() + ->staticKeys() + ->environment($this->company_gateway->getConfigField('testMode') ? Environment::sandbox() : Environment::production()) + ->publicKey($this->company_gateway->getConfigField('publicApiKey')) + ->secretKey($this->company_gateway->getConfigField('secretApiKey')); + $this->gateway = $builder->build(); + } else { - $builder = CheckoutDefaultSdk::staticKeys(); - $builder->setPublicKey($config['public']); // optional, only required for operations related with tokens - $builder->setSecretKey($config['secret']); - $builder->setEnvironment($config['sandbox'] ? Environment::sandbox() : Environment::production()); - $this->gateway = $builder->build(); - } + + $builder = CheckoutSdk::builder()->staticKeys() + ->publicKey($this->company_gateway->getConfigField('publicApiKey')) + ->secretKey($this->company_gateway->getConfigField('secretApiKey')) + ->environment($this->company_gateway->getConfigField('testMode') ? Environment::sandbox() : Environment::production()); + $this->gateway = $builder->build(); + + } return $this; } /** * Process different view depending on payment type + * * @param int $gateway_type_id The gateway type - * @return string The view string + * @return string The view string */ public function viewForType($gateway_type_id) { return 'gateways.checkout.credit_card.pay'; } - + + /** + * Authorize View + * + * @param array $data + * @return \Illuminate\View\View + */ public function authorizeView($data) { return $this->payment_method->authorizeView($data); } - + + /** + * Authorize Response + * + * @param array $data + * @return \Illuminate\View\View + */ public function authorizeResponse($data) { return $this->payment_method->authorizeResponse($data); @@ -165,7 +180,7 @@ class CheckoutComPaymentDriver extends BaseDriver * Payment View * * @param array $data Payment data array - * @return \Illuminate\View\View + * @return \Illuminate\View\View */ public function processPaymentView(array $data) { @@ -176,13 +191,19 @@ class CheckoutComPaymentDriver extends BaseDriver * Process the payment response * * @param \Illuminate\Http\Request $request The payment request - * @return \Illuminate\View\View + * @return \Illuminate\View\View */ public function processPaymentResponse($request) { return $this->payment_method->paymentResponse($request); } - + + /** + * Store PaymentMethod + * + * @param array $data + * @return ?ClientGatewayToken $token + */ public function storePaymentMethod(array $data) { return $this->storeGatewayToken($data); @@ -197,7 +218,7 @@ class CheckoutComPaymentDriver extends BaseDriver $request->amount = $this->convertToCheckoutAmount($amount, $this->client->getCurrencyCode()); try { - // or, refundPayment("payment_id") for a full refund + $response = $this->gateway->getPaymentsClient()->refundPayment($payment->transaction_reference, $request); return [ @@ -213,7 +234,7 @@ class CheckoutComPaymentDriver extends BaseDriver } catch (CheckoutArgumentException $e) { // Bad arguments - throw new PaymentFailed($e->getMessage(), $e->getCode()); + // throw new PaymentFailed($e->getMessage(), $e->getCode()); return [ 'transaction_reference' => null, @@ -223,9 +244,8 @@ class CheckoutComPaymentDriver extends BaseDriver 'code' => $e->getCode(), ]; } catch (CheckoutAuthorizationException $e) { - // Bad Invalid authorization - throw new PaymentFailed($e->getMessage(), $e->getCode()); + // throw new PaymentFailed("The was a problem with the Checkout Gateway Credentials.", $e->getCode()); return [ 'transaction_reference' => null, @@ -244,12 +264,9 @@ class CheckoutComPaymentDriver extends BaseDriver return $response; } catch (\Exception $e) { - if ($this->is_four_api) { - $request = new FourCustomerRequest(); - } else { - $request = new CustomerRequest(); - } - + + $request = new CustomerRequest(); + $phone = new Phone(); // $phone->number = $this->client->present()->phone(); $phone->number = substr(str_pad($this->client->present()->phone(), 6, "0", STR_PAD_RIGHT), 0, 24); @@ -262,59 +279,45 @@ class CheckoutComPaymentDriver extends BaseDriver $response = $this->gateway->getCustomersClient()->create($request); } catch (CheckoutApiException $e) { // API error - $request_id = $e->request_id; - $http_status_code = $e->http_status_code; $error_details = $e->error_details; - if (is_array($error_details)) { + if (isset($error_details['error_codes']) ?? false) { $error_details = end($e->error_details['error_codes']); + } else { + $error_details = $e->getMessage(); } - $human_exception = $error_details ? new \Exception($error_details, 400) : $e; - - - throw new PaymentFailed($human_exception); + throw new PaymentFailed($error_details, 400); } catch (CheckoutArgumentException $e) { - // Bad arguments - $error_details = $e->error_details; - - if (is_array($error_details)) { - $error_details = end($e->error_details['error_codes']); - } - - $human_exception = $error_details ? new \Exception($error_details, 400) : $e; - - throw new PaymentFailed($human_exception); + throw new PaymentFailed($e->getMessage(), $e->getCode()); } catch (CheckoutAuthorizationException $e) { // Bad Invalid authorization - - $error_details = $e->error_details; - - if (is_array($error_details)) { - $error_details = end($e->error_details['error_codes']); - } - $human_exception = $error_details ? new \Exception($error_details, 400) : $e; - - throw new PaymentFailed($human_exception); + throw new PaymentFailed("Checkout Gateway credentials are invalid", 400); } return $response; } } - + + /** + * Boots a request for a token payment + * + * @param string $token + * @return PreviousPaymentRequest | PaymentRequest + */ public function bootTokenRequest($token) { if ($this->is_four_api) { $token_source = new SourceRequestIdSource(); $token_source->id = $token; - $request = new PaymentRequest(); + $request = new PreviousPaymentRequest(); $request->source = $token_source; } else { $token_source = new RequestIdSource(); $token_source->id = $token; - $request = new PaymentsPaymentRequest(); + $request = new PaymentRequest(); $request->source = $token_source; } @@ -325,6 +328,8 @@ class CheckoutComPaymentDriver extends BaseDriver { $amount = array_sum(array_column($payment_hash->invoices(), 'amount')) + $payment_hash->fee_total; $invoice = Invoice::query()->whereIn('id', $this->transformKeys(array_column($payment_hash->invoices(), 'invoice_id')))->withTrashed()->first(); + $this->client = $invoice->client; + $this->payment_hash = $payment_hash; $this->init(); @@ -340,7 +345,6 @@ class CheckoutComPaymentDriver extends BaseDriver $request->request->add(['payment_hash' => $payment_hash->hash]); try { - // $response = $this->gateway->payments()->request($payment); $response = $this->gateway->getPaymentsClient()->requestPayment($paymentRequest); if ($response['status'] == 'Authorized') { @@ -386,25 +390,27 @@ class CheckoutComPaymentDriver extends BaseDriver return false; } - } catch (Exception | CheckoutApiException $e) { + } catch (CheckoutApiException $e) { + $this->unWindGatewayFees($payment_hash); - $message = $e->getMessage(); - $error_details = ''; + $error_details = $e->error_details; - if (property_exists($e, 'error_details')) { - $error_details = $e->error_details; + if (isset($error_details['error_codes']) ?? false) { + $error_details = end($e->error_details['error_codes']); + } else { + $error_details = $e->getMessage(); } - + $data = [ 'status' => $e->error_details, 'error_type' => '', 'error_code' => $e->getCode(), 'param' => '', - 'message' => $message, + 'message' => $e->getMessage(), ]; - $this->sendFailureMail($message); + $this->sendFailureMail($e->getMessage()); SystemLogger::dispatch( $data, @@ -425,8 +431,7 @@ class CheckoutComPaymentDriver extends BaseDriver if($request->header('cko-signature') == hash_hmac('sha256', $webhook_payload, $this->company_gateway->company->company_key)) { CheckoutWebhook::dispatch($request->all(), $request->company_key, $this->company_gateway->id)->delay(10); - } - else { + } else { nlog("Hash Mismatch = {$request->header('cko-signature')} ".hash_hmac('sha256', $webhook_payload, $this->company_gateway->company->company_key)); nlog($request->all()); } diff --git a/app/Services/Payment/RefundPayment.php b/app/Services/Payment/RefundPayment.php index 007f1df6efbf..b5b67358abcf 100644 --- a/app/Services/Payment/RefundPayment.php +++ b/app/Services/Payment/RefundPayment.php @@ -88,7 +88,7 @@ class RefundPayment /** * Process the refund through the gateway. * - * @var array $response + * $response * [ * 'transaction_reference' => (string), * 'transaction_response' => (string), diff --git a/composer.lock b/composer.lock index fb13b2f575ac..ba232aa837fc 100644 --- a/composer.lock +++ b/composer.lock @@ -525,16 +525,16 @@ }, { "name": "aws/aws-sdk-php", - "version": "3.280.2", + "version": "3.281.4", "source": { "type": "git", "url": "https://github.com/aws/aws-sdk-php.git", - "reference": "d68b83b3bc39b70bf33e9b8b5166facbe3e4fe9b" + "reference": "c37035bcfb67a9d54f91dae303b3fe8f98ea59f4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/d68b83b3bc39b70bf33e9b8b5166facbe3e4fe9b", - "reference": "d68b83b3bc39b70bf33e9b8b5166facbe3e4fe9b", + "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/c37035bcfb67a9d54f91dae303b3fe8f98ea59f4", + "reference": "c37035bcfb67a9d54f91dae303b3fe8f98ea59f4", "shasum": "" }, "require": { @@ -614,9 +614,9 @@ "support": { "forum": "https://forums.aws.amazon.com/forum.jspa?forumID=80", "issues": "https://github.com/aws/aws-sdk-php/issues", - "source": "https://github.com/aws/aws-sdk-php/tree/3.280.2" + "source": "https://github.com/aws/aws-sdk-php/tree/3.281.4" }, - "time": "2023-09-01T18:06:10+00:00" + "time": "2023-09-11T18:07:49+00:00" }, { "name": "bacon/bacon-qr-code", @@ -830,16 +830,16 @@ }, { "name": "checkout/checkout-sdk-php", - "version": "3.0.13", + "version": "3.0.14", "source": { "type": "git", "url": "https://github.com/checkout/checkout-sdk-php.git", - "reference": "09f50d3df10f99681b535b53c395d2ee1ddab22b" + "reference": "e8a34d34abac3fb6e7b2227731eb2e75f6ff036f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/checkout/checkout-sdk-php/zipball/09f50d3df10f99681b535b53c395d2ee1ddab22b", - "reference": "09f50d3df10f99681b535b53c395d2ee1ddab22b", + "url": "https://api.github.com/repos/checkout/checkout-sdk-php/zipball/e8a34d34abac3fb6e7b2227731eb2e75f6ff036f", + "reference": "e8a34d34abac3fb6e7b2227731eb2e75f6ff036f", "shasum": "" }, "require": { @@ -892,9 +892,9 @@ ], "support": { "issues": "https://github.com/checkout/checkout-sdk-php/issues", - "source": "https://github.com/checkout/checkout-sdk-php/tree/3.0.13" + "source": "https://github.com/checkout/checkout-sdk-php/tree/3.0.14" }, - "time": "2023-06-09T09:09:30+00:00" + "time": "2023-09-07T11:00:14+00:00" }, { "name": "cleverit/ubl_invoice", @@ -2586,16 +2586,16 @@ }, { "name": "google/apiclient-services", - "version": "v0.314.0", + "version": "v0.315.0", "source": { "type": "git", "url": "https://github.com/googleapis/google-api-php-client-services.git", - "reference": "fe2f7513dc5a4a6cf82715fd0edf7589423d6535" + "reference": "9fe675be642888cded64be861891901f092ab72d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/googleapis/google-api-php-client-services/zipball/fe2f7513dc5a4a6cf82715fd0edf7589423d6535", - "reference": "fe2f7513dc5a4a6cf82715fd0edf7589423d6535", + "url": "https://api.github.com/repos/googleapis/google-api-php-client-services/zipball/9fe675be642888cded64be861891901f092ab72d", + "reference": "9fe675be642888cded64be861891901f092ab72d", "shasum": "" }, "require": { @@ -2624,22 +2624,22 @@ ], "support": { "issues": "https://github.com/googleapis/google-api-php-client-services/issues", - "source": "https://github.com/googleapis/google-api-php-client-services/tree/v0.314.0" + "source": "https://github.com/googleapis/google-api-php-client-services/tree/v0.315.0" }, - "time": "2023-09-03T01:04:12+00:00" + "time": "2023-09-10T01:10:37+00:00" }, { "name": "google/auth", - "version": "v1.29.1", + "version": "v1.30.0", "source": { "type": "git", "url": "https://github.com/googleapis/google-auth-library-php.git", - "reference": "f199ed635b945e5adfd3c1a203543d8d86aff239" + "reference": "6028b072aa444d7edecbed603431322026704627" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/googleapis/google-auth-library-php/zipball/f199ed635b945e5adfd3c1a203543d8d86aff239", - "reference": "f199ed635b945e5adfd3c1a203543d8d86aff239", + "url": "https://api.github.com/repos/googleapis/google-auth-library-php/zipball/6028b072aa444d7edecbed603431322026704627", + "reference": "6028b072aa444d7edecbed603431322026704627", "shasum": "" }, "require": { @@ -2682,9 +2682,9 @@ "support": { "docs": "https://googleapis.github.io/google-auth-library-php/main/", "issues": "https://github.com/googleapis/google-auth-library-php/issues", - "source": "https://github.com/googleapis/google-auth-library-php/tree/v1.29.1" + "source": "https://github.com/googleapis/google-auth-library-php/tree/v1.30.0" }, - "time": "2023-08-23T08:49:35+00:00" + "time": "2023-09-07T19:13:44+00:00" }, { "name": "graham-campbell/result-type", @@ -4331,16 +4331,16 @@ }, { "name": "laravel/framework", - "version": "v10.21.0", + "version": "v10.22.0", "source": { "type": "git", "url": "https://github.com/laravel/framework.git", - "reference": "96b15c7ac382a9adb4a56d40c640e782d669a112" + "reference": "9234388a895206d4e1df37342b61adc67e5c5d31" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/framework/zipball/96b15c7ac382a9adb4a56d40c640e782d669a112", - "reference": "96b15c7ac382a9adb4a56d40c640e782d669a112", + "url": "https://api.github.com/repos/laravel/framework/zipball/9234388a895206d4e1df37342b61adc67e5c5d31", + "reference": "9234388a895206d4e1df37342b61adc67e5c5d31", "shasum": "" }, "require": { @@ -4527,7 +4527,7 @@ "issues": "https://github.com/laravel/framework/issues", "source": "https://github.com/laravel/framework" }, - "time": "2023-08-29T13:55:56+00:00" + "time": "2023-09-05T13:20:01+00:00" }, { "name": "laravel/prompts", @@ -4700,16 +4700,16 @@ }, { "name": "laravel/socialite", - "version": "v5.8.1", + "version": "v5.9.0", "source": { "type": "git", "url": "https://github.com/laravel/socialite.git", - "reference": "9989b4530331597fae811bca240bf4e8f15e804b" + "reference": "14acfa3262875f180fba51efe3c7aaa089a9ef24" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/socialite/zipball/9989b4530331597fae811bca240bf4e8f15e804b", - "reference": "9989b4530331597fae811bca240bf4e8f15e804b", + "url": "https://api.github.com/repos/laravel/socialite/zipball/14acfa3262875f180fba51efe3c7aaa089a9ef24", + "reference": "14acfa3262875f180fba51efe3c7aaa089a9ef24", "shasum": "" }, "require": { @@ -4766,7 +4766,7 @@ "issues": "https://github.com/laravel/socialite/issues", "source": "https://github.com/laravel/socialite" }, - "time": "2023-08-21T13:06:52+00:00" + "time": "2023-09-05T15:20:21+00:00" }, { "name": "laravel/tinker", @@ -5315,16 +5315,16 @@ }, { "name": "league/flysystem", - "version": "3.15.1", + "version": "3.16.0", "source": { "type": "git", "url": "https://github.com/thephpleague/flysystem.git", - "reference": "a141d430414fcb8bf797a18716b09f759a385bed" + "reference": "4fdf372ca6b63c6e281b1c01a624349ccb757729" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/thephpleague/flysystem/zipball/a141d430414fcb8bf797a18716b09f759a385bed", - "reference": "a141d430414fcb8bf797a18716b09f759a385bed", + "url": "https://api.github.com/repos/thephpleague/flysystem/zipball/4fdf372ca6b63c6e281b1c01a624349ccb757729", + "reference": "4fdf372ca6b63c6e281b1c01a624349ccb757729", "shasum": "" }, "require": { @@ -5333,6 +5333,8 @@ "php": "^8.0.2" }, "conflict": { + "async-aws/core": "<1.19.0", + "async-aws/s3": "<1.14.0", "aws/aws-sdk-php": "3.209.31 || 3.210.0", "guzzlehttp/guzzle": "<7.0", "guzzlehttp/ringphp": "<1.1.1", @@ -5352,7 +5354,7 @@ "microsoft/azure-storage-blob": "^1.1", "phpseclib/phpseclib": "^3.0.14", "phpstan/phpstan": "^0.12.26", - "phpunit/phpunit": "^9.5.11", + "phpunit/phpunit": "^9.5.11|^10.0", "sabre/dav": "^4.3.1" }, "type": "library", @@ -5387,7 +5389,7 @@ ], "support": { "issues": "https://github.com/thephpleague/flysystem/issues", - "source": "https://github.com/thephpleague/flysystem/tree/3.15.1" + "source": "https://github.com/thephpleague/flysystem/tree/3.16.0" }, "funding": [ { @@ -5399,20 +5401,20 @@ "type": "github" } ], - "time": "2023-05-04T09:04:26+00:00" + "time": "2023-09-07T19:22:17+00:00" }, { "name": "league/flysystem-aws-s3-v3", - "version": "3.15.0", + "version": "3.16.0", "source": { "type": "git", "url": "https://github.com/thephpleague/flysystem-aws-s3-v3.git", - "reference": "d8de61ee10b6a607e7996cff388c5a3a663e8c8a" + "reference": "ded9ba346bb01cb9cc4cc7f2743c2c0e14d18e1c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/thephpleague/flysystem-aws-s3-v3/zipball/d8de61ee10b6a607e7996cff388c5a3a663e8c8a", - "reference": "d8de61ee10b6a607e7996cff388c5a3a663e8c8a", + "url": "https://api.github.com/repos/thephpleague/flysystem-aws-s3-v3/zipball/ded9ba346bb01cb9cc4cc7f2743c2c0e14d18e1c", + "reference": "ded9ba346bb01cb9cc4cc7f2743c2c0e14d18e1c", "shasum": "" }, "require": { @@ -5453,7 +5455,7 @@ ], "support": { "issues": "https://github.com/thephpleague/flysystem-aws-s3-v3/issues", - "source": "https://github.com/thephpleague/flysystem-aws-s3-v3/tree/3.15.0" + "source": "https://github.com/thephpleague/flysystem-aws-s3-v3/tree/3.16.0" }, "funding": [ { @@ -5465,20 +5467,20 @@ "type": "github" } ], - "time": "2023-05-02T20:02:14+00:00" + "time": "2023-08-30T10:14:57+00:00" }, { "name": "league/flysystem-local", - "version": "3.15.0", + "version": "3.16.0", "source": { "type": "git", "url": "https://github.com/thephpleague/flysystem-local.git", - "reference": "543f64c397fefdf9cfeac443ffb6beff602796b3" + "reference": "ec7383f25642e6fd4bb0c9554fc2311245391781" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/thephpleague/flysystem-local/zipball/543f64c397fefdf9cfeac443ffb6beff602796b3", - "reference": "543f64c397fefdf9cfeac443ffb6beff602796b3", + "url": "https://api.github.com/repos/thephpleague/flysystem-local/zipball/ec7383f25642e6fd4bb0c9554fc2311245391781", + "reference": "ec7383f25642e6fd4bb0c9554fc2311245391781", "shasum": "" }, "require": { @@ -5513,7 +5515,7 @@ ], "support": { "issues": "https://github.com/thephpleague/flysystem-local/issues", - "source": "https://github.com/thephpleague/flysystem-local/tree/3.15.0" + "source": "https://github.com/thephpleague/flysystem-local/tree/3.16.0" }, "funding": [ { @@ -5525,7 +5527,7 @@ "type": "github" } ], - "time": "2023-05-02T20:02:14+00:00" + "time": "2023-08-30T10:23:59+00:00" }, { "name": "league/fractal", @@ -5867,16 +5869,16 @@ }, { "name": "microsoft/microsoft-graph", - "version": "1.105.0", + "version": "1.106.0", "source": { "type": "git", "url": "https://github.com/microsoftgraph/msgraph-sdk-php.git", - "reference": "d137bb44a1f4ec949c814471ee94265db002fc2c" + "reference": "a9f43d74131bb13cb1b5a999101d486b26601b8f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/microsoftgraph/msgraph-sdk-php/zipball/d137bb44a1f4ec949c814471ee94265db002fc2c", - "reference": "d137bb44a1f4ec949c814471ee94265db002fc2c", + "url": "https://api.github.com/repos/microsoftgraph/msgraph-sdk-php/zipball/a9f43d74131bb13cb1b5a999101d486b26601b8f", + "reference": "a9f43d74131bb13cb1b5a999101d486b26601b8f", "shasum": "" }, "require": { @@ -5913,9 +5915,9 @@ "homepage": "https://developer.microsoft.com/en-us/graph", "support": { "issues": "https://github.com/microsoftgraph/msgraph-sdk-php/issues", - "source": "https://github.com/microsoftgraph/msgraph-sdk-php/tree/1.105.0" + "source": "https://github.com/microsoftgraph/msgraph-sdk-php/tree/1.106.0" }, - "time": "2023-08-22T13:28:28+00:00" + "time": "2023-09-08T06:02:27+00:00" }, { "name": "mollie/mollie-api-php", @@ -6403,16 +6405,16 @@ }, { "name": "nesbot/carbon", - "version": "2.69.0", + "version": "2.70.0", "source": { "type": "git", "url": "https://github.com/briannesbitt/Carbon.git", - "reference": "4308217830e4ca445583a37d1bf4aff4153fa81c" + "reference": "d3298b38ea8612e5f77d38d1a99438e42f70341d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/briannesbitt/Carbon/zipball/4308217830e4ca445583a37d1bf4aff4153fa81c", - "reference": "4308217830e4ca445583a37d1bf4aff4153fa81c", + "url": "https://api.github.com/repos/briannesbitt/Carbon/zipball/d3298b38ea8612e5f77d38d1a99438e42f70341d", + "reference": "d3298b38ea8612e5f77d38d1a99438e42f70341d", "shasum": "" }, "require": { @@ -6505,7 +6507,7 @@ "type": "tidelift" } ], - "time": "2023-08-03T09:00:52+00:00" + "time": "2023-09-07T16:43:50+00:00" }, { "name": "nette/schema", @@ -7366,6 +7368,7 @@ "issues": "https://github.com/PayFast/payfast-php-sdk/issues", "source": "https://github.com/PayFast/payfast-php-sdk/tree/v1.1.4" }, + "abandoned": true, "time": "2022-12-20T10:39:51+00:00" }, { @@ -8169,16 +8172,16 @@ }, { "name": "phpstan/phpdoc-parser", - "version": "1.23.1", + "version": "1.24.0", "source": { "type": "git", "url": "https://github.com/phpstan/phpdoc-parser.git", - "reference": "846ae76eef31c6d7790fac9bc399ecee45160b26" + "reference": "3510b0a6274cc42f7219367cb3abfc123ffa09d6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/846ae76eef31c6d7790fac9bc399ecee45160b26", - "reference": "846ae76eef31c6d7790fac9bc399ecee45160b26", + "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/3510b0a6274cc42f7219367cb3abfc123ffa09d6", + "reference": "3510b0a6274cc42f7219367cb3abfc123ffa09d6", "shasum": "" }, "require": { @@ -8210,9 +8213,9 @@ "description": "PHPDoc parser with support for nullable, intersection and generic types", "support": { "issues": "https://github.com/phpstan/phpdoc-parser/issues", - "source": "https://github.com/phpstan/phpdoc-parser/tree/1.23.1" + "source": "https://github.com/phpstan/phpdoc-parser/tree/1.24.0" }, - "time": "2023-08-03T16:32:59+00:00" + "time": "2023-09-07T20:46:32+00:00" }, { "name": "pragmarx/google2fa", @@ -9152,16 +9155,16 @@ }, { "name": "razorpay/razorpay", - "version": "2.8.6", + "version": "2.8.7", "source": { "type": "git", "url": "https://github.com/razorpay/razorpay-php.git", - "reference": "c151dadbb3d0a64d92574e9789b970196e629cac" + "reference": "2180c8c3c39678623f5cb8f639c39a706de14c44" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/razorpay/razorpay-php/zipball/c151dadbb3d0a64d92574e9789b970196e629cac", - "reference": "c151dadbb3d0a64d92574e9789b970196e629cac", + "url": "https://api.github.com/repos/razorpay/razorpay-php/zipball/2180c8c3c39678623f5cb8f639c39a706de14c44", + "reference": "2180c8c3c39678623f5cb8f639c39a706de14c44", "shasum": "" }, "require": { @@ -9213,20 +9216,20 @@ "issues": "https://github.com/Razorpay/razorpay-php/issues", "source": "https://github.com/Razorpay/razorpay-php" }, - "time": "2023-06-16T10:31:14+00:00" + "time": "2023-09-11T08:31:26+00:00" }, { "name": "rmccue/requests", - "version": "v2.0.7", + "version": "v2.0.8", "source": { "type": "git", "url": "https://github.com/WordPress/Requests.git", - "reference": "e14a6f4e7438d3f8da3f2657759e6367b906ee23" + "reference": "fae75bcb83d9d00d0e31ee86a472a036f9f91519" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/WordPress/Requests/zipball/e14a6f4e7438d3f8da3f2657759e6367b906ee23", - "reference": "e14a6f4e7438d3f8da3f2657759e6367b906ee23", + "url": "https://api.github.com/repos/WordPress/Requests/zipball/fae75bcb83d9d00d0e31ee86a472a036f9f91519", + "reference": "fae75bcb83d9d00d0e31ee86a472a036f9f91519", "shasum": "" }, "require": { @@ -9244,6 +9247,12 @@ "wp-coding-standards/wpcs": "^2.0", "yoast/phpunit-polyfills": "^1.0.0" }, + "suggest": { + "art4/requests-psr18-adapter": "For using Requests as a PSR-18 HTTP Client", + "ext-curl": "For improved performance", + "ext-openssl": "For secure transport support", + "ext-zlib": "For improved performance when decompressing encoded streams" + }, "type": "library", "autoload": { "files": [ @@ -9294,7 +9303,7 @@ "issues": "https://github.com/WordPress/Requests/issues", "source": "https://github.com/WordPress/Requests" }, - "time": "2023-06-02T07:35:42+00:00" + "time": "2023-09-11T08:27:57+00:00" }, { "name": "sabre/uri", @@ -9583,16 +9592,16 @@ }, { "name": "sentry/sentry-laravel", - "version": "3.7.3", + "version": "3.8.0", "source": { "type": "git", "url": "https://github.com/getsentry/sentry-laravel.git", - "reference": "2aee4ad217be8ef04ffcde6e9f7dd17af5a3b0bf" + "reference": "c7e7611553f9f90af10ed98dde1a680220f02e4d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/getsentry/sentry-laravel/zipball/2aee4ad217be8ef04ffcde6e9f7dd17af5a3b0bf", - "reference": "2aee4ad217be8ef04ffcde6e9f7dd17af5a3b0bf", + "url": "https://api.github.com/repos/getsentry/sentry-laravel/zipball/c7e7611553f9f90af10ed98dde1a680220f02e4d", + "reference": "c7e7611553f9f90af10ed98dde1a680220f02e4d", "shasum": "" }, "require": { @@ -9605,6 +9614,7 @@ }, "require-dev": { "friendsofphp/php-cs-fixer": "^3.11", + "laravel/folio": "^1.0", "laravel/framework": "^6.0 | ^7.0 | ^8.0 | ^9.0 | ^10.0", "mockery/mockery": "^1.3", "orchestra/testbench": "^4.7 | ^5.1 | ^6.0 | ^7.0 | ^8.0", @@ -9658,7 +9668,7 @@ ], "support": { "issues": "https://github.com/getsentry/sentry-laravel/issues", - "source": "https://github.com/getsentry/sentry-laravel/tree/3.7.3" + "source": "https://github.com/getsentry/sentry-laravel/tree/3.8.0" }, "funding": [ { @@ -9670,7 +9680,7 @@ "type": "custom" } ], - "time": "2023-08-03T10:10:23+00:00" + "time": "2023-09-05T11:02:34+00:00" }, { "name": "setasign/fpdf", @@ -9906,26 +9916,26 @@ }, { "name": "socialiteproviders/apple", - "version": "5.5.2", + "version": "5.6.0", "source": { "type": "git", "url": "https://github.com/SocialiteProviders/Apple.git", - "reference": "82febc9805143d1ebea6c3e66db402d43bf511e1" + "reference": "4f0f06e463824f0df6151c768db2fec6610ea055" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/SocialiteProviders/Apple/zipball/82febc9805143d1ebea6c3e66db402d43bf511e1", - "reference": "82febc9805143d1ebea6c3e66db402d43bf511e1", + "url": "https://api.github.com/repos/SocialiteProviders/Apple/zipball/4f0f06e463824f0df6151c768db2fec6610ea055", + "reference": "4f0f06e463824f0df6151c768db2fec6610ea055", "shasum": "" }, "require": { "ext-json": "*", "ext-openssl": "*", - "firebase/php-jwt": "^6.2", + "firebase/php-jwt": "^6.8", "lcobucci/clock": "^2.0 || ^3.0", "lcobucci/jwt": "^4.1.5 || ^5.0.0", - "php": "^7.4 || ^8.0", - "socialiteproviders/manager": "~4.0" + "php": "^8.0", + "socialiteproviders/manager": "^4.4" }, "suggest": { "ahilmurugesan/socialite-apple-helper": "Automatic Apple client key generation and management." @@ -9974,7 +9984,7 @@ "issues": "https://github.com/socialiteproviders/providers/issues", "source": "https://github.com/socialiteproviders/providers" }, - "time": "2023-05-24T23:29:11+00:00" + "time": "2023-09-11T21:59:09+00:00" }, { "name": "socialiteproviders/manager", @@ -15068,16 +15078,16 @@ }, { "name": "friendsofphp/php-cs-fixer", - "version": "v3.25.1", + "version": "v3.26.1", "source": { "type": "git", "url": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer.git", - "reference": "8e21d69801de6b5ecb0dbe0bcdf967b335b1260b" + "reference": "d023ba6684055f6ea1da1352d8a02baca0426983" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/8e21d69801de6b5ecb0dbe0bcdf967b335b1260b", - "reference": "8e21d69801de6b5ecb0dbe0bcdf967b335b1260b", + "url": "https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/d023ba6684055f6ea1da1352d8a02baca0426983", + "reference": "d023ba6684055f6ea1da1352d8a02baca0426983", "shasum": "" }, "require": { @@ -15151,7 +15161,7 @@ ], "support": { "issues": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/issues", - "source": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/tree/v3.25.1" + "source": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/tree/v3.26.1" }, "funding": [ { @@ -15159,7 +15169,7 @@ "type": "github" } ], - "time": "2023-09-04T01:22:52+00:00" + "time": "2023-09-08T19:09:07+00:00" }, { "name": "hamcrest/hamcrest-php", @@ -15870,16 +15880,16 @@ }, { "name": "phpstan/phpstan", - "version": "1.10.32", + "version": "1.10.33", "source": { "type": "git", "url": "https://github.com/phpstan/phpstan.git", - "reference": "c47e47d3ab03137c0e121e77c4d2cb58672f6d44" + "reference": "03b1cf9f814ba0863c4e9affea49a4d1ed9a2ed1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan/zipball/c47e47d3ab03137c0e121e77c4d2cb58672f6d44", - "reference": "c47e47d3ab03137c0e121e77c4d2cb58672f6d44", + "url": "https://api.github.com/repos/phpstan/phpstan/zipball/03b1cf9f814ba0863c4e9affea49a4d1ed9a2ed1", + "reference": "03b1cf9f814ba0863c4e9affea49a4d1ed9a2ed1", "shasum": "" }, "require": { @@ -15928,7 +15938,7 @@ "type": "tidelift" } ], - "time": "2023-08-24T21:54:50+00:00" + "time": "2023-09-04T12:20:53+00:00" }, { "name": "phpunit/php-code-coverage", @@ -16253,16 +16263,16 @@ }, { "name": "phpunit/phpunit", - "version": "10.3.2", + "version": "10.3.3", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "0dafb1175c366dd274eaa9a625e914451506bcd1" + "reference": "241ed4dd0db1c096984e62d414c4e1ac8d5dbff4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/0dafb1175c366dd274eaa9a625e914451506bcd1", - "reference": "0dafb1175c366dd274eaa9a625e914451506bcd1", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/241ed4dd0db1c096984e62d414c4e1ac8d5dbff4", + "reference": "241ed4dd0db1c096984e62d414c4e1ac8d5dbff4", "shasum": "" }, "require": { @@ -16334,7 +16344,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/phpunit/issues", "security": "https://github.com/sebastianbergmann/phpunit/security/policy", - "source": "https://github.com/sebastianbergmann/phpunit/tree/10.3.2" + "source": "https://github.com/sebastianbergmann/phpunit/tree/10.3.3" }, "funding": [ { @@ -16350,7 +16360,7 @@ "type": "tidelift" } ], - "time": "2023-08-15T05:34:23+00:00" + "time": "2023-09-05T04:34:51+00:00" }, { "name": "sebastian/cli-parser", @@ -16787,16 +16797,16 @@ }, { "name": "sebastian/exporter", - "version": "5.0.0", + "version": "5.0.1", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/exporter.git", - "reference": "f3ec4bf931c0b31e5b413f5b4fc970a7d03338c0" + "reference": "32ff03d078fed1279c4ec9a407d08c5e9febb480" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/f3ec4bf931c0b31e5b413f5b4fc970a7d03338c0", - "reference": "f3ec4bf931c0b31e5b413f5b4fc970a7d03338c0", + "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/32ff03d078fed1279c4ec9a407d08c5e9febb480", + "reference": "32ff03d078fed1279c4ec9a407d08c5e9febb480", "shasum": "" }, "require": { @@ -16852,7 +16862,8 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/exporter/issues", - "source": "https://github.com/sebastianbergmann/exporter/tree/5.0.0" + "security": "https://github.com/sebastianbergmann/exporter/security/policy", + "source": "https://github.com/sebastianbergmann/exporter/tree/5.0.1" }, "funding": [ { @@ -16860,7 +16871,7 @@ "type": "github" } ], - "time": "2023-02-03T07:06:49+00:00" + "time": "2023-09-08T04:46:58+00:00" }, { "name": "sebastian/global-state", From 6c2ab8fff51b8421882f4697353f0b2e63c7bc6e Mon Sep 17 00:00:00 2001 From: David Bomba Date: Tue, 12 Sep 2023 10:30:42 +1000 Subject: [PATCH 08/20] Set Client on webhook return Checkout.com --- app/PaymentDrivers/CheckoutComPaymentDriver.php | 1 + 1 file changed, 1 insertion(+) diff --git a/app/PaymentDrivers/CheckoutComPaymentDriver.php b/app/PaymentDrivers/CheckoutComPaymentDriver.php index a4ca85e95032..103220c63d6d 100644 --- a/app/PaymentDrivers/CheckoutComPaymentDriver.php +++ b/app/PaymentDrivers/CheckoutComPaymentDriver.php @@ -447,6 +447,7 @@ class CheckoutComPaymentDriver extends BaseDriver //11-08-2022 check the user is authenticated if (!Auth::guard('contact')->check()) { $client = $request->getClient(); + $this->client = $client; auth()->guard('contact')->loginUsingId($client->contacts()->first()->id, true); } From 597abfa5844670273fe97e933e58e0fdc18bf750 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Tue, 12 Sep 2023 11:01:14 +1000 Subject: [PATCH 09/20] Update exports for previews --- app/Export/CSV/BaseExport.php | 8 ++- app/Export/CSV/CreditExport.php | 6 +-- app/Export/CSV/DocumentExport.php | 23 +-------- app/Export/CSV/InvoiceItemExport.php | 27 ++++++---- app/Export/CSV/PurchaseOrderExport.php | 5 +- app/Export/CSV/PurchaseOrderItemExport.php | 57 ++++++++++++++++++---- 6 files changed, 80 insertions(+), 46 deletions(-) diff --git a/app/Export/CSV/BaseExport.php b/app/Export/CSV/BaseExport.php index 483c1c0b4a48..63b1ec5c3c11 100644 --- a/app/Export/CSV/BaseExport.php +++ b/app/Export/CSV/BaseExport.php @@ -13,13 +13,15 @@ namespace App\Export\CSV; use App\Utils\Number; use App\Models\Client; -use App\Models\ClientContact; use App\Utils\Helpers; use App\Models\Company; use App\Models\Expense; use App\Models\Invoice; use App\Models\Payment; +use App\Models\Document; use League\Fractal\Manager; +use App\Models\ClientContact; +use App\Models\PurchaseOrder; use Illuminate\Support\Carbon; use App\Utils\Traits\MakesHash; use App\Transformers\TaskTransformer; @@ -1034,10 +1036,14 @@ class BaseExport { $class = get_class($resource); + $entity = ''; + match ($class) { Invoice::class => $entity = 'invoice', Expense::class => $entity = 'expense', + Document::class => $entity = 'document', ClientContact::class => $entity = 'contact', + PurchaseOrder::class => $entity = 'purchase_order', default => $entity = 'invoice', }; diff --git a/app/Export/CSV/CreditExport.php b/app/Export/CSV/CreditExport.php index ca0fde8bfed6..2d4cc8447fca 100644 --- a/app/Export/CSV/CreditExport.php +++ b/app/Export/CSV/CreditExport.php @@ -19,7 +19,7 @@ use App\Models\Company; use App\Libraries\MultiDB; use Illuminate\Support\Facades\App; use App\Transformers\CreditTransformer; -use Illuminate\Contracts\Database\Eloquent\Builder; +use Illuminate\Database\Eloquent\Builder; class CreditExport extends BaseExport { @@ -66,12 +66,12 @@ class CreditExport extends BaseExport $column_key = $value; $clean_row[$key]['entity'] = $report_keys[0]; $clean_row[$key]['id'] = $report_keys[1] ?? $report_keys[0]; - $clean_row[$key]['hashed_id'] = $report_keys[0] == 'credit' ? null : $credit->{$report_keys[0]}->hashed_id ?? null; + $clean_row[$key]['hashed_id'] = $report_keys[0] == 'credit' ? null : $resource->{$report_keys[0]}->hashed_id ?? null; $clean_row[$key]['value'] = $row[$column_key]; $clean_row[$key]['identifier'] = $value; if(in_array($clean_row[$key]['id'], ['paid_to_date','total_taxes','amount', 'balance', 'partial', 'refunded', 'applied','unit_cost','cost','price'])) - $clean_row[$key]['display_value'] = Number::formatMoney($row[$column_key], $credit->client); + $clean_row[$key]['display_value'] = Number::formatMoney($row[$column_key], $resource->client); else $clean_row[$key]['display_value'] = $row[$column_key]; diff --git a/app/Export/CSV/DocumentExport.php b/app/Export/CSV/DocumentExport.php index 391fe14050a3..701b1bc3ffe0 100644 --- a/app/Export/CSV/DocumentExport.php +++ b/app/Export/CSV/DocumentExport.php @@ -16,7 +16,7 @@ use App\Models\Company; use App\Models\Document; use App\Transformers\DocumentTransformer; use App\Utils\Ninja; -use Illuminate\Contracts\Database\Eloquent\Builder; +use Illuminate\Database\Eloquent\Builder; use Illuminate\Support\Facades\App; use League\Csv\Writer; @@ -62,27 +62,6 @@ class DocumentExport extends BaseExport return array_merge(['columns' => $header], $report); } - private function processMetaData(array $row, Document $document): array - { - $clean_row = []; - foreach (array_values($this->input['report_keys']) as $key => $value) { - - $report_keys = explode(".", $value); - - $column_key = $value; - $clean_row[$key]['entity'] = $report_keys[0]; - $clean_row[$key]['id'] = $report_keys[1] ?? $report_keys[0]; - $clean_row[$key]['hashed_id'] = $report_keys[0] == 'document' ? null : $document->{$report_keys[0]}->hashed_id ?? null; - $clean_row[$key]['value'] = $row[$column_key]; - $clean_row[$key]['identifier'] = $value; - - $clean_row[$key]['display_value'] = $row[$column_key]; - - } - - return $clean_row; - } - private function init(): Builder { diff --git a/app/Export/CSV/InvoiceItemExport.php b/app/Export/CSV/InvoiceItemExport.php index 92e85fcd348a..1c420edbfbd6 100644 --- a/app/Export/CSV/InvoiceItemExport.php +++ b/app/Export/CSV/InvoiceItemExport.php @@ -16,7 +16,7 @@ use App\Models\Company; use App\Models\Invoice; use App\Transformers\InvoiceTransformer; use App\Utils\Ninja; -use Illuminate\Contracts\Database\Eloquent\Builder; +use Illuminate\Database\Eloquent\Builder; use Illuminate\Support\Facades\App; use League\Csv\Writer; @@ -33,6 +33,8 @@ class InvoiceItemExport extends BaseExport private array $storage_array = []; + private array $storage_item_array = []; + private array $decorate_keys = [ 'client', 'currency_id', @@ -62,7 +64,8 @@ class InvoiceItemExport extends BaseExport $query = Invoice::query() ->withTrashed() - ->with('client')->where('company_id', $this->company->id) + ->with('client') + ->where('company_id', $this->company->id) ->where('is_deleted', 0); $query = $this->addDateRange($query); @@ -81,16 +84,22 @@ class InvoiceItemExport extends BaseExport return ['identifier' => $value, 'display_value' => $headerdisplay[$value]]; })->toArray(); - $items = $query->cursor() - ->map(function ($resource) { + nlog($query->count()); + + $query->cursor() + ->each(function ($resource) { $this->iterateItems($resource); - $row = $this->processMetaData($this->storage_array[0], $resource); + + foreach($this->storage_array as $row) { + $this->storage_item_array[] = $this->processMetaData($row, $resource); + } + $this->storage_array = []; - return $row; - })->toArray(); - + + }); + + return array_merge(['columns' => $header], $this->storage_item_array); - return array_merge(['columns' => $header], $items); } diff --git a/app/Export/CSV/PurchaseOrderExport.php b/app/Export/CSV/PurchaseOrderExport.php index ffee39eee336..ed506f61050e 100644 --- a/app/Export/CSV/PurchaseOrderExport.php +++ b/app/Export/CSV/PurchaseOrderExport.php @@ -19,7 +19,7 @@ use App\Libraries\MultiDB; use App\Models\PurchaseOrder; use Illuminate\Support\Facades\App; use App\Transformers\PurchaseOrderTransformer; -use Illuminate\Contracts\Database\Eloquent\Builder; +use Illuminate\Database\Eloquent\Builder; class PurchaseOrderExport extends BaseExport { @@ -119,7 +119,8 @@ class PurchaseOrderExport extends BaseExport $report = $query->cursor() ->map(function ($resource) { - return $this->buildRow($resource); + $row = $this->buildRow($resource); + return $this->processMetaData($row, $resource); })->toArray(); return array_merge(['columns' => $header], $report); diff --git a/app/Export/CSV/PurchaseOrderItemExport.php b/app/Export/CSV/PurchaseOrderItemExport.php index ec63f8388f14..a117279c2588 100644 --- a/app/Export/CSV/PurchaseOrderItemExport.php +++ b/app/Export/CSV/PurchaseOrderItemExport.php @@ -11,14 +11,14 @@ namespace App\Export\CSV; -use App\Libraries\MultiDB; -use App\Models\Company; -use App\Models\PurchaseOrder; -use App\Transformers\PurchaseOrderTransformer; use App\Utils\Ninja; -use Illuminate\Contracts\Database\Eloquent\Builder; -use Illuminate\Support\Facades\App; use League\Csv\Writer; +use App\Models\Company; +use App\Libraries\MultiDB; +use App\Models\PurchaseOrder; +use Illuminate\Support\Facades\App; +use Illuminate\Database\Eloquent\Builder; +use App\Transformers\PurchaseOrderTransformer; class PurchaseOrderItemExport extends BaseExport { @@ -33,6 +33,8 @@ class PurchaseOrderItemExport extends BaseExport private array $storage_array = []; + private array $storage_item_array = []; + public function __construct(Company $company, array $input) { $this->company = $company; @@ -50,7 +52,6 @@ class PurchaseOrderItemExport extends BaseExport $t->replace(Ninja::transformTranslations($this->company->settings)); if (count($this->input['report_keys']) == 0) { - // $this->force_keys = true; $this->input['report_keys'] = array_values($this->mergeItemsKeys('purchase_order_report_keys')); } @@ -78,9 +79,18 @@ class PurchaseOrderItemExport extends BaseExport $query->cursor() ->each(function ($resource) { $this->iterateItems($resource); + + $this->storage_item_array = []; + + foreach($this->storage_array as $row) { + $this->storage_item_array[] = $this->processMetaData($row, $resource); + } + + $this->storage_array = []; + }); - return array_merge(['columns' => $header], $this->storage_array); + return array_merge(['columns' => $header], $this->storage_item_array); } public function run() @@ -113,7 +123,7 @@ class PurchaseOrderItemExport extends BaseExport foreach ($purchase_order->line_items as $item) { $item_array = []; - foreach (array_values($this->input['report_keys']) as $key) { //items iterator produces item array + foreach (array_values(array_intersect($this->input['report_keys'], $this->item_report_keys)) as $key) { //items iterator produces item array if (str_contains($key, "item.")) { @@ -190,4 +200,33 @@ class PurchaseOrderItemExport extends BaseExport return $entity; } + + public function processMetaData(array $row, $resource): array + { + $entity = 'purchase_order'; + $clean_row = []; + + foreach (array_values($this->input['report_keys']) as $key => $value) { + + $report_keys = explode(".", $value); + + $column_key = $value; + + if($value == 'type_id' || $value == 'item.type_id') + $column_key = 'type'; + + if($value == 'tax_id' || $value == 'item.tax_id') + $column_key = 'tax_category'; + + $clean_row[$key]['entity'] = $report_keys[0]; + $clean_row[$key]['id'] = $report_keys[1] ?? $report_keys[0]; + $clean_row[$key]['hashed_id'] = $report_keys[0] == $entity ? null : $resource->{$report_keys[0]}->hashed_id ?? null; + $clean_row[$key]['value'] = isset($row[$column_key]) ? $row[$column_key] : $row[$report_keys[1]]; + $clean_row[$key]['identifier'] = $value; + $clean_row[$key]['display_value'] = isset($row[$column_key]) ? $row[$column_key] : $row[$report_keys[1]]; + + } + + return $clean_row; + } } From 3539c6b372ff87d7c3e61f39b273966f0ee2e054 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Tue, 12 Sep 2023 11:03:19 +1000 Subject: [PATCH 10/20] Fixes for tests: --- tests/Feature/QuoteTest.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/Feature/QuoteTest.php b/tests/Feature/QuoteTest.php index 957286739fb0..57ebde27b3e6 100644 --- a/tests/Feature/QuoteTest.php +++ b/tests/Feature/QuoteTest.php @@ -74,19 +74,19 @@ class QuoteTest extends TestCase 'line_items' =>[ [ 'type_id' => 2, - 'unit_cost' => 200, + 'cost' => 200, 'quantity' => 2, 'notes' => 'Test200', ], [ 'type_id' => 2, - 'unit_cost' => 100, + 'cost' => 100, 'quantity' => 1, 'notes' => 'Test100', ], [ 'type_id' => 1, - 'unit_cost' => 10, + 'cost' => 10, 'quantity' => 1, 'notes' => 'Test', ], @@ -171,7 +171,7 @@ class QuoteTest extends TestCase $project = Project::find($this->decodePrimaryKey($res['data'][0]['project_id'])); - $this->assertEquals($project->name, ctrans('texts.quote_number_short') . " " . $this->quote->number); + $this->assertEquals($project->name, ctrans('texts.quote_number_short') . " " . $this->quote->number."[{$this->quote->client->present()->name()}]"); } public function testQuoteList() From 86a6910e255e4c29c1bf6c387b2817857d5d7c84 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Tue, 12 Sep 2023 11:22:59 +1000 Subject: [PATCH 11/20] Fixes for Recurring Invoice Export --- app/Export/CSV/BaseExport.php | 51 +++++++- app/Export/CSV/InvoiceExport.php | 3 +- app/Export/CSV/InvoiceItemExport.php | 32 +---- app/Export/CSV/PurchaseOrderItemExport.php | 32 +---- app/Export/CSV/QuoteExport.php | 5 +- app/Export/CSV/QuoteItemExport.php | 25 ++-- app/Export/CSV/RecurringInvoiceExport.php | 116 +++++++----------- .../Reports/QuoteItemReportController.php | 23 +++- .../RecurringInvoiceReportController.php | 27 ++-- 9 files changed, 156 insertions(+), 158 deletions(-) diff --git a/app/Export/CSV/BaseExport.php b/app/Export/CSV/BaseExport.php index 63b1ec5c3c11..0fa46ba477a0 100644 --- a/app/Export/CSV/BaseExport.php +++ b/app/Export/CSV/BaseExport.php @@ -11,8 +11,10 @@ namespace App\Export\CSV; +use App\Models\Quote; use App\Utils\Number; use App\Models\Client; +use App\Models\Credit; use App\Utils\Helpers; use App\Models\Company; use App\Models\Expense; @@ -22,6 +24,7 @@ use App\Models\Document; use League\Fractal\Manager; use App\Models\ClientContact; use App\Models\PurchaseOrder; +use App\Models\RecurringInvoice; use Illuminate\Support\Carbon; use App\Utils\Traits\MakesHash; use App\Transformers\TaskTransformer; @@ -1037,9 +1040,12 @@ class BaseExport $class = get_class($resource); $entity = ''; - + match ($class) { Invoice::class => $entity = 'invoice', + RecurringInvoice::class => $entity = 'recurring_invoice', + Quote::class => $entity = 'quote', + Credit::class => $entity = 'credit', Expense::class => $entity = 'expense', Document::class => $entity = 'document', ClientContact::class => $entity = 'contact', @@ -1066,4 +1072,47 @@ class BaseExport return $clean_row; } + public function processItemMetaData(array $row, $resource): array + { + $class = get_class($resource); + + $entity = ''; + + match ($class) { + Invoice::class => $entity = 'invoice', + Quote::class => $entity = 'quote', + Credit::class => $entity = 'credit', + Expense::class => $entity = 'expense', + Document::class => $entity = 'document', + ClientContact::class => $entity = 'contact', + PurchaseOrder::class => $entity = 'purchase_order', + default => $entity = 'invoice', + }; + + $clean_row = []; + + foreach (array_values($this->input['report_keys']) as $key => $value) { + + $report_keys = explode(".", $value); + + $column_key = $value; + + if($value == 'type_id' || $value == 'item.type_id') + $column_key = 'type'; + + if($value == 'tax_id' || $value == 'item.tax_id') + $column_key = 'tax_category'; + + $clean_row[$key]['entity'] = $report_keys[0]; + $clean_row[$key]['id'] = $report_keys[1] ?? $report_keys[0]; + $clean_row[$key]['hashed_id'] = $report_keys[0] == $entity ? null : $resource->{$report_keys[0]}->hashed_id ?? null; + $clean_row[$key]['value'] = isset($row[$column_key]) ? $row[$column_key] : $row[$report_keys[1]]; + $clean_row[$key]['identifier'] = $value; + $clean_row[$key]['display_value'] = isset($row[$column_key]) ? $row[$column_key] : $row[$report_keys[1]]; + + } + + return $clean_row; + } + } diff --git a/app/Export/CSV/InvoiceExport.php b/app/Export/CSV/InvoiceExport.php index 4123940a7695..f8cc1cfe9348 100644 --- a/app/Export/CSV/InvoiceExport.php +++ b/app/Export/CSV/InvoiceExport.php @@ -20,7 +20,7 @@ use App\Libraries\MultiDB; use App\Export\CSV\BaseExport; use Illuminate\Support\Facades\App; use App\Transformers\InvoiceTransformer; -use Illuminate\Contracts\Database\Eloquent\Builder; +use Illuminate\Database\Eloquent\Builder; class InvoiceExport extends BaseExport { @@ -95,7 +95,6 @@ class InvoiceExport extends BaseExport //insert the header $this->csv->insertOne($this->buildHeader()); - $query->cursor() ->each(function ($invoice) { $this->csv->insertOne($this->buildRow($invoice)); diff --git a/app/Export/CSV/InvoiceItemExport.php b/app/Export/CSV/InvoiceItemExport.php index 1c420edbfbd6..4db01226725d 100644 --- a/app/Export/CSV/InvoiceItemExport.php +++ b/app/Export/CSV/InvoiceItemExport.php @@ -84,14 +84,13 @@ class InvoiceItemExport extends BaseExport return ['identifier' => $value, 'display_value' => $headerdisplay[$value]]; })->toArray(); - nlog($query->count()); $query->cursor() ->each(function ($resource) { $this->iterateItems($resource); foreach($this->storage_array as $row) { - $this->storage_item_array[] = $this->processMetaData($row, $resource); + $this->storage_item_array[] = $this->processItemMetaData($row, $resource); } $this->storage_array = []; @@ -204,33 +203,4 @@ class InvoiceItemExport extends BaseExport return $entity; } - public function processMetaData(array $row, $resource): array - { - $entity = 'invoice'; - $clean_row = []; - - foreach (array_values($this->input['report_keys']) as $key => $value) { - - $report_keys = explode(".", $value); - - $column_key = $value; - - if($value == 'type_id' || $value == 'item.type_id') - $column_key = 'type'; - - if($value == 'tax_id' || $value == 'item.tax_id') - $column_key = 'tax_category'; - - $clean_row[$key]['entity'] = $report_keys[0]; - $clean_row[$key]['id'] = $report_keys[1] ?? $report_keys[0]; - $clean_row[$key]['hashed_id'] = $report_keys[0] == $entity ? null : $resource->{$report_keys[0]}->hashed_id ?? null; - $clean_row[$key]['value'] = isset($row[$column_key]) ? $row[$column_key] : $row[$report_keys[1]]; - $clean_row[$key]['identifier'] = $value; - $clean_row[$key]['display_value'] = isset($row[$column_key]) ? $row[$column_key] : $row[$report_keys[1]]; - - } - - return $clean_row; - } - } diff --git a/app/Export/CSV/PurchaseOrderItemExport.php b/app/Export/CSV/PurchaseOrderItemExport.php index a117279c2588..8859a431ce3b 100644 --- a/app/Export/CSV/PurchaseOrderItemExport.php +++ b/app/Export/CSV/PurchaseOrderItemExport.php @@ -80,10 +80,8 @@ class PurchaseOrderItemExport extends BaseExport ->each(function ($resource) { $this->iterateItems($resource); - $this->storage_item_array = []; - foreach($this->storage_array as $row) { - $this->storage_item_array[] = $this->processMetaData($row, $resource); + $this->storage_item_array[] = $this->processItemMetaData($row, $resource); } $this->storage_array = []; @@ -201,32 +199,4 @@ class PurchaseOrderItemExport extends BaseExport return $entity; } - public function processMetaData(array $row, $resource): array - { - $entity = 'purchase_order'; - $clean_row = []; - - foreach (array_values($this->input['report_keys']) as $key => $value) { - - $report_keys = explode(".", $value); - - $column_key = $value; - - if($value == 'type_id' || $value == 'item.type_id') - $column_key = 'type'; - - if($value == 'tax_id' || $value == 'item.tax_id') - $column_key = 'tax_category'; - - $clean_row[$key]['entity'] = $report_keys[0]; - $clean_row[$key]['id'] = $report_keys[1] ?? $report_keys[0]; - $clean_row[$key]['hashed_id'] = $report_keys[0] == $entity ? null : $resource->{$report_keys[0]}->hashed_id ?? null; - $clean_row[$key]['value'] = isset($row[$column_key]) ? $row[$column_key] : $row[$report_keys[1]]; - $clean_row[$key]['identifier'] = $value; - $clean_row[$key]['display_value'] = isset($row[$column_key]) ? $row[$column_key] : $row[$report_keys[1]]; - - } - - return $clean_row; - } } diff --git a/app/Export/CSV/QuoteExport.php b/app/Export/CSV/QuoteExport.php index a84becb20eb2..de2813608537 100644 --- a/app/Export/CSV/QuoteExport.php +++ b/app/Export/CSV/QuoteExport.php @@ -16,7 +16,7 @@ use App\Models\Company; use App\Models\Quote; use App\Transformers\QuoteTransformer; use App\Utils\Ninja; -use Illuminate\Contracts\Database\Eloquent\Builder; +use Illuminate\Database\Eloquent\Builder; use Illuminate\Support\Facades\App; use League\Csv\Writer; @@ -80,7 +80,8 @@ class QuoteExport extends BaseExport $report = $query->cursor() ->map(function ($resource) { - return $this->buildRow($resource); + $row = $this->buildRow($resource); + return $this->processMetaData($row, $resource); })->toArray(); return array_merge(['columns' => $header], $report); diff --git a/app/Export/CSV/QuoteItemExport.php b/app/Export/CSV/QuoteItemExport.php index a2f78d16ce41..774b50a774b2 100644 --- a/app/Export/CSV/QuoteItemExport.php +++ b/app/Export/CSV/QuoteItemExport.php @@ -16,7 +16,7 @@ use App\Models\Company; use App\Models\Quote; use App\Transformers\QuoteTransformer; use App\Utils\Ninja; -use Illuminate\Contracts\Database\Eloquent\Builder; +use Illuminate\Database\Eloquent\Builder; use Illuminate\Support\Facades\App; use League\Csv\Writer; @@ -29,7 +29,8 @@ class QuoteItemExport extends BaseExport public Writer $csv; - private array $storage_array; + private array $storage_array = []; + private array $storage_item_array = []; private array $decorate_keys = [ 'client', @@ -77,12 +78,20 @@ class QuoteItemExport extends BaseExport return ['identifier' => $value, 'display_value' => $headerdisplay[$value]]; })->toArray(); - $query->cursor() - ->each(function ($resource) { - $this->iterateItems($resource); - }); - - return array_merge(['columns' => $header], $this->storage_array); + $query->cursor() + ->each(function ($resource) { + $this->iterateItems($resource); + + foreach($this->storage_array as $row) { + $this->storage_item_array[] = $this->processItemMetaData($row, $resource); + } + + $this->storage_array = []; + + }); + + return array_merge(['columns' => $header], $this->storage_item_array); + } diff --git a/app/Export/CSV/RecurringInvoiceExport.php b/app/Export/CSV/RecurringInvoiceExport.php index 330f29695c83..8daf3388ca19 100644 --- a/app/Export/CSV/RecurringInvoiceExport.php +++ b/app/Export/CSV/RecurringInvoiceExport.php @@ -16,6 +16,7 @@ use App\Models\Company; use App\Models\RecurringInvoice; use App\Transformers\RecurringInvoiceTransformer; use App\Utils\Ninja; +use Illuminate\Database\Eloquent\Builder; use Illuminate\Support\Facades\App; use League\Csv\Writer; @@ -28,55 +29,6 @@ class RecurringInvoiceExport extends BaseExport public Writer $csv; - public array $entity_keys = [ - 'amount' => 'amount', - 'balance' => 'balance', - 'client' => 'client_id', - // 'custom_surcharge1' => 'custom_surcharge1', - // 'custom_surcharge2' => 'custom_surcharge2', - // 'custom_surcharge3' => 'custom_surcharge3', - // 'custom_surcharge4' => 'custom_surcharge4', - 'custom_value1' => 'custom_value1', - 'custom_value2' => 'custom_value2', - 'custom_value3' => 'custom_value3', - 'custom_value4' => 'custom_value4', - 'date' => 'date', - 'discount' => 'discount', - 'due_date' => 'due_date', - 'exchange_rate' => 'exchange_rate', - 'footer' => 'footer', - 'number' => 'number', - 'paid_to_date' => 'paid_to_date', - 'partial' => 'partial', - 'partial_due_date' => 'partial_due_date', - 'po_number' => 'po_number', - 'private_notes' => 'private_notes', - 'public_notes' => 'public_notes', - 'next_send_date' => 'next_send_date', - 'status' => 'status_id', - 'tax_name1' => 'tax_name1', - 'tax_name2' => 'tax_name2', - 'tax_name3' => 'tax_name3', - 'tax_rate1' => 'tax_rate1', - 'tax_rate2' => 'tax_rate2', - 'tax_rate3' => 'tax_rate3', - 'terms' => 'terms', - 'total_taxes' => 'total_taxes', - 'currency' => 'currency_id', - 'vendor' => 'vendor_id', - 'project' => 'project_id', - 'frequency_id' => 'frequency_id', - ]; - - private array $decorate_keys = [ - 'country', - 'client', - 'currency', - 'status', - 'vendor', - 'project', - ]; - public function __construct(Company $company, array $input) { $this->company = $company; @@ -84,7 +36,7 @@ class RecurringInvoiceExport extends BaseExport $this->invoice_transformer = new RecurringInvoiceTransformer(); } - public function run() + public function init(): Builder { MultiDB::setDb($this->company->db); App::forgetInstance('translator'); @@ -92,23 +44,33 @@ class RecurringInvoiceExport extends BaseExport $t = app('translator'); $t->replace(Ninja::transformTranslations($this->company->settings)); - //load the CSV document from a string - $this->csv = Writer::createFromString(); - if (count($this->input['report_keys']) == 0) { - $this->input['report_keys'] = array_values($this->entity_keys); + $this->input['report_keys'] = array_values($this->recurring_invoice_report_keys); } - //insert the header - $this->csv->insertOne($this->buildHeader()); - $query = RecurringInvoice::query() ->withTrashed() - ->with('client')->where('company_id', $this->company->id) + ->with('client') + ->where('company_id', $this->company->id) ->where('is_deleted', 0); $query = $this->addDateRange($query); + return $query; + + } + + public function run() + { + + $query = $this->init(); + + //load the CSV document from a string + $this->csv = Writer::createFromString(); + + //insert the header + $this->csv->insertOne($this->buildHeader()); + $query->cursor() ->each(function ($invoice) { $this->csv->insertOne($this->buildRow($invoice)); @@ -117,6 +79,27 @@ class RecurringInvoiceExport extends BaseExport return $this->csv->toString(); } + + public function returnJson() + { + $query = $this->init(); + + $headerdisplay = $this->buildHeader(); + + $header = collect($this->input['report_keys'])->map(function ($key, $value) use($headerdisplay){ + return ['identifier' => $value, 'display_value' => $headerdisplay[$value]]; + })->toArray(); + + $report = $query->cursor() + ->map(function ($resource) { + $row = $this->buildRow($resource); + return $this->processMetaData($row, $resource); + })->toArray(); + + return array_merge(['columns' => $header], $report); + } + + private function buildRow(RecurringInvoice $invoice) :array { $transformed_invoice = $this->invoice_transformer->transform($invoice); @@ -124,22 +107,13 @@ class RecurringInvoiceExport extends BaseExport $entity = []; foreach (array_values($this->input['report_keys']) as $key) { - $keyval = array_search($key, $this->entity_keys); - if(!$keyval) { - $keyval = array_search(str_replace("recurring_invoice.", "", $key), $this->entity_keys) ?? $key; - } + $parts = explode('.', $key); - if(!$keyval) { - $keyval = $key; - } - - if (array_key_exists($key, $transformed_invoice)) { - $entity[$keyval] = $transformed_invoice[$key]; - } elseif (array_key_exists($keyval, $transformed_invoice)) { - $entity[$keyval] = $transformed_invoice[$keyval]; + if (is_array($parts) && $parts[0] == 'recurring_invoice' && array_key_exists($parts[1], $transformed_invoice)) { + $entity[$key] = $transformed_invoice[$parts[1]]; } else { - $entity[$keyval] = $this->resolveKey($keyval, $invoice, $this->invoice_transformer); + $entity[$key] = $this->resolveKey($key, $invoice, $this->invoice_transformer); } } diff --git a/app/Http/Controllers/Reports/QuoteItemReportController.php b/app/Http/Controllers/Reports/QuoteItemReportController.php index 66fb6c5a5fe1..78295f1ddc7c 100644 --- a/app/Http/Controllers/Reports/QuoteItemReportController.php +++ b/app/Http/Controllers/Reports/QuoteItemReportController.php @@ -11,12 +11,13 @@ namespace App\Http\Controllers\Reports; +use Illuminate\Http\Response; +use App\Utils\Traits\MakesHash; +use App\Jobs\Report\SendToAdmin; +use App\Jobs\Report\PreviewReport; use App\Export\CSV\QuoteItemExport; use App\Http\Controllers\BaseController; use App\Http\Requests\Report\GenericReportRequest; -use App\Jobs\Report\SendToAdmin; -use App\Utils\Traits\MakesHash; -use Illuminate\Http\Response; class QuoteItemReportController extends BaseController { @@ -62,14 +63,26 @@ class QuoteItemReportController extends BaseController */ public function __invoke(GenericReportRequest $request) { + /** @var \App\Models\User $user */ + $user = auth()->user(); + if ($request->has('send_email') && $request->get('send_email')) { - SendToAdmin::dispatch(auth()->user()->company(), $request->all(), QuoteItemExport::class, $this->filename); + SendToAdmin::dispatch($user->company(), $request->all(), QuoteItemExport::class, $this->filename); return response()->json(['message' => 'working...'], 200); } // expect a list of visible fields, or use the default - $export = new QuoteItemExport(auth()->user()->company(), $request->all()); + if($request->has('output') && $request->input('output') == 'json') { + + $hash = \Illuminate\Support\Str::uuid(); + + PreviewReport::dispatch($user->company(), $request->all(), QuoteItemExport::class, $hash); + + return response()->json(['message' => $hash], 200); + } + + $export = new QuoteItemExport($user->company(), $request->all()); $csv = $export->run(); diff --git a/app/Http/Controllers/Reports/RecurringInvoiceReportController.php b/app/Http/Controllers/Reports/RecurringInvoiceReportController.php index eaae55bd1351..26eb279106f2 100644 --- a/app/Http/Controllers/Reports/RecurringInvoiceReportController.php +++ b/app/Http/Controllers/Reports/RecurringInvoiceReportController.php @@ -11,12 +11,13 @@ namespace App\Http\Controllers\Reports; -use App\Export\CSV\RecurringInvoiceExport; -use App\Http\Controllers\BaseController; -use App\Http\Requests\Report\GenericReportRequest; -use App\Jobs\Report\SendToAdmin; -use App\Utils\Traits\MakesHash; use Illuminate\Http\Response; +use App\Utils\Traits\MakesHash; +use App\Jobs\Report\SendToAdmin; +use App\Jobs\Report\PreviewReport; +use App\Http\Controllers\BaseController; +use App\Export\CSV\RecurringInvoiceExport; +use App\Http\Requests\Report\GenericReportRequest; class RecurringInvoiceReportController extends BaseController { @@ -31,14 +32,26 @@ class RecurringInvoiceReportController extends BaseController public function __invoke(GenericReportRequest $request) { + /** @var \App\Models\User $user */ + $user = auth()->user(); + if ($request->has('send_email') && $request->get('send_email')) { - SendToAdmin::dispatch(auth()->user()->company(), $request->all(), RecurringInvoiceExport::class, $this->filename); + SendToAdmin::dispatch($user->company(), $request->all(), RecurringInvoiceExport::class, $this->filename); return response()->json(['message' => 'working...'], 200); } // expect a list of visible fields, or use the default - $export = new RecurringInvoiceExport(auth()->user()->company(), $request->all()); + if($request->has('output') && $request->input('output') == 'json') { + + $hash = \Illuminate\Support\Str::uuid(); + + PreviewReport::dispatch($user->company(), $request->all(), RecurringInvoiceExport::class, $hash); + + return response()->json(['message' => $hash], 200); + } + + $export = new RecurringInvoiceExport($user->company(), $request->all()); $csv = $export->run(); From 173c8efaed3c6439b2f776a53b722e400838b801 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Tue, 12 Sep 2023 11:55:11 +1000 Subject: [PATCH 12/20] Report exports --- app/Export/CSV/BaseExport.php | 27 ++++- app/Export/CSV/PaymentExport.php | 40 +------ app/Export/CSV/ProductExport.php | 6 +- app/Export/CSV/TaskExport.php | 106 +++++++++++++----- .../Reports/InvoiceItemReportController.php | 1 - .../Reports/TaskReportController.php | 23 +++- lang/en/texts.php | 1 + 7 files changed, 128 insertions(+), 76 deletions(-) diff --git a/app/Export/CSV/BaseExport.php b/app/Export/CSV/BaseExport.php index 0fa46ba477a0..12f48e057b15 100644 --- a/app/Export/CSV/BaseExport.php +++ b/app/Export/CSV/BaseExport.php @@ -31,6 +31,8 @@ use App\Transformers\TaskTransformer; use App\Transformers\PaymentTransformer; use Illuminate\Database\Eloquent\Builder; use League\Fractal\Serializer\ArraySerializer; +use App\Models\Product; +use App\Models\Task; class BaseExport { @@ -235,8 +237,8 @@ class BaseExport ]; protected array $product_report_keys = [ - 'project' => 'project_id', - 'vendor' => 'vendor_id', + // 'project' => 'project_id', + // 'vendor' => 'vendor_id', 'custom_value1' => 'custom_value1', 'custom_value2' => 'custom_value2', 'custom_value3' => 'custom_value3', @@ -252,6 +254,10 @@ class BaseExport 'tax_name1' => 'tax_name1', 'tax_name2' => 'tax_name2', 'tax_name3' => 'tax_name3', + 'image' => 'product_image', + 'tax_category' => 'tax_id', + 'max_quantity' => 'max_quantity', + 'in_stock_quantity' => 'in_stock_quantity', ]; protected array $item_report_keys = [ @@ -992,6 +998,7 @@ class BaseExport $key = str_replace('payment.', '', $key); $key = str_replace('expense.', '', $key); $key = str_replace('product.', '', $key); + $key = str_replace('task.', '', $key); if(stripos($value, 'custom_value') !== false) { @@ -1015,7 +1022,7 @@ class BaseExport $custom_field_string = strlen($helper->makeCustomField($this->company->custom_fields, $entity)) > 1 ? $helper->makeCustomField($this->company->custom_fields, $entity) : ctrans("texts.{$parts[1]}"); $header[] = ctrans("texts.{$parts[0]}") . " " . $custom_field_string; } - elseif(count($parts) == 2 && in_array(substr($original_key, 0, -1), ['credit','quote','invoice','purchase_order','recurring_invoice'])){ + elseif(count($parts) == 2 && in_array(substr($original_key, 0, -1), ['credit','quote','invoice','purchase_order','recurring_invoice','task'])){ $custom_field_string = strlen($helper->makeCustomField($this->company->custom_fields, "product".substr($original_key,-1))) > 1 ? $helper->makeCustomField($this->company->custom_fields, "product".substr($original_key,-1)) : ctrans("texts.{$parts[1]}"); $header[] = ctrans("texts.{$parts[0]}") . " " . $custom_field_string; } @@ -1050,6 +1057,9 @@ class BaseExport Document::class => $entity = 'document', ClientContact::class => $entity = 'contact', PurchaseOrder::class => $entity = 'purchase_order', + Payment::class => $entity = 'payment', + Product::class => $entity = 'product', + Task::class => $entity = 'task', default => $entity = 'invoice', }; @@ -1060,6 +1070,17 @@ class BaseExport $report_keys = explode(".", $value); $column_key = $value; + + if($value == 'product_image') { + $column_key = 'image'; + $value = 'image'; + } + + if($value == 'tax_id') { + $column_key = 'tax_category'; + $value = 'tax_category'; + } + $clean_row[$key]['entity'] = $report_keys[0]; $clean_row[$key]['id'] = $report_keys[1] ?? $report_keys[0]; $clean_row[$key]['hashed_id'] = $report_keys[0] == $entity ? null : $resource->{$report_keys[0]}->hashed_id ?? null; diff --git a/app/Export/CSV/PaymentExport.php b/app/Export/CSV/PaymentExport.php index 930be240b75f..b868bd23ea71 100644 --- a/app/Export/CSV/PaymentExport.php +++ b/app/Export/CSV/PaymentExport.php @@ -16,7 +16,7 @@ use App\Models\Company; use App\Models\Payment; use App\Transformers\PaymentTransformer; use App\Utils\Ninja; -use Illuminate\Contracts\Database\Eloquent\Builder; +use Illuminate\Database\Eloquent\Builder; use Illuminate\Support\Facades\App; use League\Csv\Writer; @@ -28,40 +28,6 @@ class PaymentExport extends BaseExport public Writer $csv; - // public array $entity_keys = [ - // 'amount' => 'amount', - // 'applied' => 'applied', - // 'client' => 'client_id', - // 'currency' => 'currency_id', - // 'custom_value1' => 'custom_value1', - // 'custom_value2' => 'custom_value2', - // 'custom_value3' => 'custom_value3', - // 'custom_value4' => 'custom_value4', - // 'date' => 'date', - // 'exchange_currency' => 'exchange_currency_id', - // 'gateway' => 'gateway_type_id', - // 'number' => 'number', - // 'private_notes' => 'private_notes', - // 'project' => 'project_id', - // 'refunded' => 'refunded', - // 'status' => 'status_id', - // 'transaction_reference' => 'transaction_reference', - // 'type' => 'type_id', - // 'vendor' => 'vendor_id', - // 'invoices' => 'invoices', - // ]; - - // private array $decorate_keys = [ - // 'vendor', - // 'status', - // 'project', - // 'client', - // 'currency', - // 'exchange_currency', - // 'type', - // 'invoices', - // ]; - public function __construct(Company $company, array $input) { $this->company = $company; @@ -105,12 +71,12 @@ class PaymentExport extends BaseExport $report = $query->cursor() ->map(function ($resource) { - return $this->buildRow($resource); + $row = $this->buildRow($resource); + return $this->processMetaData($row, $resource); })->toArray(); return array_merge(['columns' => $header], $report); - } public function run() diff --git a/app/Export/CSV/ProductExport.php b/app/Export/CSV/ProductExport.php index a4c5bbf7535c..0097040ba622 100644 --- a/app/Export/CSV/ProductExport.php +++ b/app/Export/CSV/ProductExport.php @@ -13,11 +13,10 @@ namespace App\Export\CSV; use App\Libraries\MultiDB; use App\Models\Company; -use App\Models\Document; use App\Models\Product; use App\Transformers\ProductTransformer; use App\Utils\Ninja; -use Illuminate\Contracts\Database\Eloquent\Builder; +use Illuminate\Database\Eloquent\Builder; use Illuminate\Support\Facades\App; use League\Csv\Writer; @@ -48,7 +47,8 @@ class ProductExport extends BaseExport $report = $query->cursor() ->map(function ($resource) { - return $this->buildRow($resource); + $row = $this->buildRow($resource); + return $this->processMetaData($row, $resource); })->toArray(); return array_merge(['columns' => $header], $report); diff --git a/app/Export/CSV/TaskExport.php b/app/Export/CSV/TaskExport.php index 387bda902043..cd50dc8fe524 100644 --- a/app/Export/CSV/TaskExport.php +++ b/app/Export/CSV/TaskExport.php @@ -18,6 +18,7 @@ use App\Models\Task; use App\Models\Timezone; use App\Transformers\TaskTransformer; use App\Utils\Ninja; +use Illuminate\Database\Eloquent\Builder; use Illuminate\Support\Carbon; use Illuminate\Support\Facades\App; use League\Csv\Writer; @@ -33,6 +34,10 @@ class TaskExport extends BaseExport public Writer $csv; + private array $storage_array = []; + + private array $storage_item_array = []; + public array $entity_keys = [ 'start_date' => 'start_date', 'end_date' => 'end_date', @@ -65,7 +70,7 @@ class TaskExport extends BaseExport $this->entity_transformer = new TaskTransformer(); } - public function run() + public function init(): Builder { MultiDB::setDb($this->company->db); App::forgetInstance('translator'); @@ -74,19 +79,12 @@ class TaskExport extends BaseExport $t->replace(Ninja::transformTranslations($this->company->settings)); $this->date_format = DateFormat::find($this->company->settings->date_format_id)->format; - - //load the CSV document from a string - $this->csv = Writer::createFromString(); - ksort($this->entity_keys); if (count($this->input['report_keys']) == 0) { - $this->input['report_keys'] = array_values($this->entity_keys); + $this->input['report_keys'] = array_values($this->task_report_keys); } - //insert the header - $this->csv->insertOne($this->buildHeader()); - $query = Task::query() ->withTrashed() ->where('company_id', $this->company->id) @@ -94,51 +92,104 @@ class TaskExport extends BaseExport $query = $this->addDateRange($query); + return $query; + + } + + public function run() + { + + $query = $this->init(); + + //load the CSV document from a string + $this->csv = Writer::createFromString(); + + //insert the header + $this->csv->insertOne($this->buildHeader()); + $query->cursor() ->each(function ($entity) { $this->buildRow($entity); }); + $this->csv->insertAll($this->storage_array); + return $this->csv->toString(); } + + public function returnJson() + { + $query = $this->init(); + + $headerdisplay = $this->buildHeader(); + + $header = collect($this->input['report_keys'])->map(function ($key, $value) use($headerdisplay){ + return ['identifier' => $value, 'display_value' => $headerdisplay[$value]]; + })->toArray(); + + $query->cursor() + ->each(function ($resource) { + + $this->buildRow($resource); + + foreach($this->storage_array as $row) + { + $this->storage_item_array[] = $this->processMetaData($row, $resource); + } + + $this->storage_array = []; + }); + + return array_merge(['columns' => $header], $this->storage_item_array); + } + private function buildRow(Task $task) { $entity = []; $transformed_entity = $this->entity_transformer->transform($task); foreach (array_values($this->input['report_keys']) as $key) { - $keyval = array_search($key, $this->entity_keys); - if(!$keyval) { - $keyval = array_search(str_replace("task.", "", $key), $this->entity_keys) ?? $key; + $parts = explode('.', $key); + + if (is_array($parts) && $parts[0] == 'task' && array_key_exists($parts[1], $transformed_entity)) { + $entity[$key] = $transformed_entity[$parts[1]]; + } elseif (array_key_exists($key, $transformed_entity)) { + $entity[$key] = $transformed_entity[$key]; + } else { + $entity[$key] = $this->resolveKey($key, $task, $this->entity_transformer); } - if(!$keyval) { - $keyval = $key; - } + // $keyval = array_search($key, $this->entity_keys); - if (array_key_exists($key, $transformed_entity)) { - $entity[$keyval] = $transformed_entity[$key]; - } elseif (array_key_exists($keyval, $transformed_entity)) { - $entity[$keyval] = $transformed_entity[$keyval]; - } - else { - $entity[$keyval] = $this->resolveKey($keyval, $task, $this->entity_transformer); - } + // if(!$keyval) { + // $keyval = array_search(str_replace("task.", "", $key), $this->entity_keys) ?? $key; + // } + + // if(!$keyval) { + // $keyval = $key; + // } + + // if (array_key_exists($key, $transformed_entity)) { + // $entity[$keyval] = $transformed_entity[$key]; + // } elseif (array_key_exists($keyval, $transformed_entity)) { + // $entity[$keyval] = $transformed_entity[$keyval]; + // } + // else { + // $entity[$keyval] = $this->resolveKey($keyval, $task, $this->entity_transformer); + // } } $entity['start_date'] = ''; $entity['end_date'] = ''; $entity['duration'] = ''; - if (is_null($task->time_log) || (is_array(json_decode($task->time_log, 1)) && count(json_decode($task->time_log, 1)) == 0)) { - $this->csv->insertOne($entity); + $this->storage_array[] = $entity; } else { $this->iterateLogs($task, $entity); } - } @@ -180,12 +231,13 @@ class TaskExport extends BaseExport $entity = $this->decorateAdvancedFields($task, $entity); - $this->csv->insertOne($entity); + $this->storage_array[] = $entity; unset($entity['start_date']); unset($entity['end_date']); unset($entity['duration']); } + } private function decorateAdvancedFields(Task $task, array $entity) :array diff --git a/app/Http/Controllers/Reports/InvoiceItemReportController.php b/app/Http/Controllers/Reports/InvoiceItemReportController.php index dc568dfad629..a124171cc66e 100644 --- a/app/Http/Controllers/Reports/InvoiceItemReportController.php +++ b/app/Http/Controllers/Reports/InvoiceItemReportController.php @@ -80,7 +80,6 @@ class InvoiceItemReportController extends BaseController return response()->json(['message' => $hash], 200); } - $export = new InvoiceItemExport($user->company(), $request->all()); diff --git a/app/Http/Controllers/Reports/TaskReportController.php b/app/Http/Controllers/Reports/TaskReportController.php index 5eff880c38de..8339a909bcb0 100644 --- a/app/Http/Controllers/Reports/TaskReportController.php +++ b/app/Http/Controllers/Reports/TaskReportController.php @@ -11,12 +11,13 @@ namespace App\Http\Controllers\Reports; +use Illuminate\Http\Response; use App\Export\CSV\TaskExport; +use App\Utils\Traits\MakesHash; +use App\Jobs\Report\SendToAdmin; +use App\Jobs\Report\PreviewReport; use App\Http\Controllers\BaseController; use App\Http\Requests\Report\GenericReportRequest; -use App\Jobs\Report\SendToAdmin; -use App\Utils\Traits\MakesHash; -use Illuminate\Http\Response; class TaskReportController extends BaseController { @@ -62,14 +63,26 @@ class TaskReportController extends BaseController */ public function __invoke(GenericReportRequest $request) { + /** @var \App\Models\User $user */ + $user = auth()->user(); + if ($request->has('send_email') && $request->get('send_email')) { - SendToAdmin::dispatch(auth()->user()->company(), $request->all(), TaskExport::class, $this->filename); + SendToAdmin::dispatch($user->company(), $request->all(), TaskExport::class, $this->filename); return response()->json(['message' => 'working...'], 200); } // expect a list of visible fields, or use the default - $export = new TaskExport(auth()->user()->company(), $request->all()); + if($request->has('output') && $request->input('output') == 'json') { + + $hash = \Illuminate\Support\Str::uuid(); + + PreviewReport::dispatch($user->company(), $request->all(), TaskExport::class, $hash); + + return response()->json(['message' => $hash], 200); + } + + $export = new TaskExport($user->company(), $request->all()); $csv = $export->run(); diff --git a/lang/en/texts.php b/lang/en/texts.php index 8be95187c7be..b67f6f745b16 100644 --- a/lang/en/texts.php +++ b/lang/en/texts.php @@ -5158,6 +5158,7 @@ $LANG = array( 'click_or_drop_files_here' => 'Click or drop files here', 'set_public' => 'Set public', 'set_private' => 'Set private', + 'in_stock_quantity' => 'Stock quantity', ); return $LANG; From bbe138ef792d73274f40656438d748d8838ba678 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Tue, 12 Sep 2023 13:02:27 +1000 Subject: [PATCH 13/20] Fixes for tests --- app/Export/CSV/RecurringInvoiceExport.php | 2 +- app/Export/CSV/TaskExport.php | 8 +-- .../Export/ReportCsvGenerationTest.php | 62 +++++++++---------- 3 files changed, 36 insertions(+), 36 deletions(-) diff --git a/app/Export/CSV/RecurringInvoiceExport.php b/app/Export/CSV/RecurringInvoiceExport.php index 8daf3388ca19..06c17eec3ff0 100644 --- a/app/Export/CSV/RecurringInvoiceExport.php +++ b/app/Export/CSV/RecurringInvoiceExport.php @@ -148,7 +148,7 @@ class RecurringInvoiceExport extends BaseExport } if (in_array('recurring_invoice.frequency_id', $this->input['report_keys']) || in_array('frequency_id', $this->input['report_keys'])) { - $entity['frequency_id'] = $invoice->frequencyForKey($invoice->frequency_id); + $entity['recurring_invoice.frequency_id'] = $invoice->frequencyForKey($invoice->frequency_id); } return $entity; diff --git a/app/Export/CSV/TaskExport.php b/app/Export/CSV/TaskExport.php index cd50dc8fe524..d7cb21e9c235 100644 --- a/app/Export/CSV/TaskExport.php +++ b/app/Export/CSV/TaskExport.php @@ -214,19 +214,19 @@ class TaskExport extends BaseExport foreach ($logs as $key => $item) { if (in_array('task.start_date', $this->input['report_keys']) || in_array('start_date', $this->input['report_keys'])) { - $entity['start_date'] = Carbon::createFromTimeStamp($item[0])->setTimezone($timezone_name)->format($date_format_default); + $entity['task.start_date'] = Carbon::createFromTimeStamp($item[0])->setTimezone($timezone_name)->format($date_format_default); } if ((in_array('task.end_date', $this->input['report_keys']) || in_array('end_date', $this->input['report_keys'])) && $item[1] > 0) { - $entity['end_date'] = Carbon::createFromTimeStamp($item[1])->setTimezone($timezone_name)->format($date_format_default); + $entity['task.end_date'] = Carbon::createFromTimeStamp($item[1])->setTimezone($timezone_name)->format($date_format_default); } if ((in_array('task.end_date', $this->input['report_keys']) || in_array('end_date', $this->input['report_keys'])) && $item[1] == 0) { - $entity['end_date'] = ctrans('texts.is_running'); + $entity['task.end_date'] = ctrans('texts.is_running'); } if (in_array('task.duration', $this->input['report_keys']) || in_array('duration', $this->input['report_keys'])) { - $entity['duration'] = $task->calcDuration(); + $entity['task.duration'] = $task->calcDuration(); } $entity = $this->decorateAdvancedFields($task, $entity); diff --git a/tests/Feature/Export/ReportCsvGenerationTest.php b/tests/Feature/Export/ReportCsvGenerationTest.php index 32e264c3e251..730f8697cbf1 100644 --- a/tests/Feature/Export/ReportCsvGenerationTest.php +++ b/tests/Feature/Export/ReportCsvGenerationTest.php @@ -488,14 +488,14 @@ class ReportCsvGenerationTest extends TestCase $csv = $response->streamedContent(); - $this->assertEquals(3600, $this->getFirstValueByColumn($csv, 'Duration')); - $this->assertEquals('test', $this->getFirstValueByColumn($csv, 'Description')); - $this->assertEquals('16/Jul/2023', $this->getFirstValueByColumn($csv, 'Start Date')); - $this->assertEquals('16/Jul/2023', $this->getFirstValueByColumn($csv, 'End Date')); - $this->assertEquals('Custom 1', $this->getFirstValueByColumn($csv, 'Custom Value 1')); - $this->assertEquals('Custom 2', $this->getFirstValueByColumn($csv, 'Custom Value 2')); - $this->assertEquals('Custom 3', $this->getFirstValueByColumn($csv, 'Custom Value 3')); - $this->assertEquals('Custom 4', $this->getFirstValueByColumn($csv, 'Custom Value 4')); + $this->assertEquals(3600, $this->getFirstValueByColumn($csv, 'Task Duration')); + $this->assertEquals('test', $this->getFirstValueByColumn($csv, 'Task Description')); + $this->assertEquals('16/Jul/2023', $this->getFirstValueByColumn($csv, 'Task Start Date')); + $this->assertEquals('16/Jul/2023', $this->getFirstValueByColumn($csv, 'Task End Date')); + $this->assertEquals('Custom 1', $this->getFirstValueByColumn($csv, 'Task Custom Value 1')); + $this->assertEquals('Custom 2', $this->getFirstValueByColumn($csv, 'Task Custom Value 2')); + $this->assertEquals('Custom 3', $this->getFirstValueByColumn($csv, 'Task Custom Value 3')); + $this->assertEquals('Custom 4', $this->getFirstValueByColumn($csv, 'Task Custom Value 4')); } @@ -1567,29 +1567,29 @@ class ReportCsvGenerationTest extends TestCase $csv = $response->streamedContent(); - $this->assertEquals('100', $this->getFirstValueByColumn($csv, 'Amount')); - $this->assertEquals('50', $this->getFirstValueByColumn($csv, 'Balance')); - $this->assertEquals('10', $this->getFirstValueByColumn($csv, 'Discount')); - $this->assertEquals('1234', $this->getFirstValueByColumn($csv, 'PO Number')); - $this->assertEquals('Public', $this->getFirstValueByColumn($csv, 'Public Notes')); - $this->assertEquals('Private', $this->getFirstValueByColumn($csv, 'Private Notes')); - $this->assertEquals('Terms', $this->getFirstValueByColumn($csv, 'Terms')); - $this->assertEquals('2020-01-01', $this->getFirstValueByColumn($csv, 'Date')); - $this->assertEquals('2021-01-02', $this->getFirstValueByColumn($csv, 'Due Date')); - $this->assertEquals('2021-01-03', $this->getFirstValueByColumn($csv, 'Partial Due Date')); - $this->assertEquals('10', $this->getFirstValueByColumn($csv, 'Partial/Deposit')); - $this->assertEquals('Custom 1', $this->getFirstValueByColumn($csv, 'Custom Value 1')); - $this->assertEquals('Custom 2', $this->getFirstValueByColumn($csv, 'Custom Value 2')); - $this->assertEquals('Custom 3', $this->getFirstValueByColumn($csv, 'Custom Value 3')); - $this->assertEquals('Custom 4', $this->getFirstValueByColumn($csv, 'Custom Value 4')); - $this->assertEquals('Footer', $this->getFirstValueByColumn($csv, 'Footer')); - $this->assertEquals('Tax 1', $this->getFirstValueByColumn($csv, 'Tax Name 1')); - $this->assertEquals('10', $this->getFirstValueByColumn($csv, 'Tax Rate 1')); - $this->assertEquals('Tax 2', $this->getFirstValueByColumn($csv, 'Tax Name 2')); - $this->assertEquals('20', $this->getFirstValueByColumn($csv, 'Tax Rate 2')); - $this->assertEquals('Tax 3', $this->getFirstValueByColumn($csv, 'Tax Name 3')); - $this->assertEquals('30', $this->getFirstValueByColumn($csv, 'Tax Rate 3')); - $this->assertEquals('Daily', $this->getFirstValueByColumn($csv, 'How Often')); + $this->assertEquals('100', $this->getFirstValueByColumn($csv, 'Recurring Invoice Amount')); + $this->assertEquals('50', $this->getFirstValueByColumn($csv, 'Recurring Invoice Balance')); + $this->assertEquals('10', $this->getFirstValueByColumn($csv, 'Recurring Invoice Discount')); + $this->assertEquals('1234', $this->getFirstValueByColumn($csv, 'Recurring Invoice PO Number')); + $this->assertEquals('Public', $this->getFirstValueByColumn($csv, 'Recurring Invoice Public Notes')); + $this->assertEquals('Private', $this->getFirstValueByColumn($csv, 'Recurring Invoice Private Notes')); + $this->assertEquals('Terms', $this->getFirstValueByColumn($csv, 'Recurring Invoice Terms')); + $this->assertEquals('2020-01-01', $this->getFirstValueByColumn($csv, 'Recurring Invoice Date')); + $this->assertEquals('2021-01-02', $this->getFirstValueByColumn($csv, 'Recurring Invoice Due Date')); + $this->assertEquals('2021-01-03', $this->getFirstValueByColumn($csv, 'Recurring Invoice Partial Due Date')); + $this->assertEquals('10', $this->getFirstValueByColumn($csv, 'Recurring Invoice Partial/Deposit')); + $this->assertEquals('Custom 1', $this->getFirstValueByColumn($csv, 'Recurring Invoice Custom Value 1')); + $this->assertEquals('Custom 2', $this->getFirstValueByColumn($csv, 'Recurring Invoice Custom Value 2')); + $this->assertEquals('Custom 3', $this->getFirstValueByColumn($csv, 'Recurring Invoice Custom Value 3')); + $this->assertEquals('Custom 4', $this->getFirstValueByColumn($csv, 'Recurring Invoice Custom Value 4')); + $this->assertEquals('Footer', $this->getFirstValueByColumn($csv, 'Recurring Invoice Footer')); + $this->assertEquals('Tax 1', $this->getFirstValueByColumn($csv, 'Recurring Invoice Tax Name 1')); + $this->assertEquals('10', $this->getFirstValueByColumn($csv, 'Recurring Invoice Tax Rate 1')); + $this->assertEquals('Tax 2', $this->getFirstValueByColumn($csv, 'Recurring Invoice Tax Name 2')); + $this->assertEquals('20', $this->getFirstValueByColumn($csv, 'Recurring Invoice Tax Rate 2')); + $this->assertEquals('Tax 3', $this->getFirstValueByColumn($csv, 'Recurring Invoice Tax Name 3')); + $this->assertEquals('30', $this->getFirstValueByColumn($csv, 'Recurring Invoice Tax Rate 3')); + $this->assertEquals('Daily', $this->getFirstValueByColumn($csv, 'Recurring Invoice How Often')); } From cfca47a542e038922b739af26ea1a8a6b5405e9b Mon Sep 17 00:00:00 2001 From: David Bomba Date: Tue, 12 Sep 2023 13:55:37 +1000 Subject: [PATCH 14/20] Fixes for react builder --- app/Console/Commands/ReactBuilder.php | 3 + app/Export/CSV/BaseExport.php | 6 +- app/Export/CSV/TaskExport.php | 67 +++----------- app/Export/CSV/VendorExport.php | 90 +++++++++---------- .../Reports/VendorReportController.php | 21 ++++- 5 files changed, 77 insertions(+), 110 deletions(-) diff --git a/app/Console/Commands/ReactBuilder.php b/app/Console/Commands/ReactBuilder.php index 430b16d90542..4bec0cefb5c5 100644 --- a/app/Console/Commands/ReactBuilder.php +++ b/app/Console/Commands/ReactBuilder.php @@ -12,6 +12,7 @@ namespace App\Console\Commands; use Illuminate\Console\Command; +use Illuminate\Support\Facades\Storage; class ReactBuilder extends Command { @@ -47,6 +48,8 @@ class ReactBuilder extends Command public function handle() { $includes = ''; + + Storage::makeDirectory(public_path('react')); $directoryIterator = new \RecursiveDirectoryIterator(public_path('react'), \RecursiveDirectoryIterator::SKIP_DOTS); diff --git a/app/Export/CSV/BaseExport.php b/app/Export/CSV/BaseExport.php index 12f48e057b15..698752b08f79 100644 --- a/app/Export/CSV/BaseExport.php +++ b/app/Export/CSV/BaseExport.php @@ -33,6 +33,7 @@ use Illuminate\Database\Eloquent\Builder; use League\Fractal\Serializer\ArraySerializer; use App\Models\Product; use App\Models\Task; +use App\Models\Vendor; class BaseExport { @@ -656,7 +657,7 @@ class BaseExport // nlog("searching for {$column}"); $transformed_invoice = false; - if($transformer instanceof PaymentTransformer) { + if($transformer instanceof PaymentTransformer && ($entity->invoice ?? false)) { $transformed_invoices = $transformer->includeInvoices($entity); $manager = new Manager(); @@ -678,7 +679,7 @@ class BaseExport } - if($transformer instanceof TaskTransformer) { + if($transformer instanceof TaskTransformer && ($entity->invoice ?? false)) { $transformed_invoice = $transformer->includeInvoice($entity); if(!$transformed_invoice) @@ -1060,6 +1061,7 @@ class BaseExport Payment::class => $entity = 'payment', Product::class => $entity = 'product', Task::class => $entity = 'task', + Vendor::class => $entity = 'vendor', default => $entity = 'invoice', }; diff --git a/app/Export/CSV/TaskExport.php b/app/Export/CSV/TaskExport.php index d7cb21e9c235..30cf6379c02f 100644 --- a/app/Export/CSV/TaskExport.php +++ b/app/Export/CSV/TaskExport.php @@ -38,31 +38,6 @@ class TaskExport extends BaseExport private array $storage_item_array = []; - public array $entity_keys = [ - 'start_date' => 'start_date', - 'end_date' => 'end_date', - 'duration' => 'duration', - 'rate' => 'rate', - 'number' => 'number', - 'description' => 'description', - 'custom_value1' => 'custom_value1', - 'custom_value2' => 'custom_value2', - 'custom_value3' => 'custom_value3', - 'custom_value4' => 'custom_value4', - 'status' => 'status_id', - 'project' => 'project_id', - ]; - - private array $decorate_keys = [ - 'status', - 'project', - 'client', - 'invoice', - 'start_date', - 'end_date', - 'duration', - ]; - public function __construct(Company $company, array $input) { $this->company = $company; @@ -140,7 +115,7 @@ class TaskExport extends BaseExport $this->storage_array = []; }); - + nlog($this->storage_item_array); return array_merge(['columns' => $header], $this->storage_item_array); } @@ -161,29 +136,11 @@ class TaskExport extends BaseExport $entity[$key] = $this->resolveKey($key, $task, $this->entity_transformer); } - // $keyval = array_search($key, $this->entity_keys); - - // if(!$keyval) { - // $keyval = array_search(str_replace("task.", "", $key), $this->entity_keys) ?? $key; - // } - - // if(!$keyval) { - // $keyval = $key; - // } - - // if (array_key_exists($key, $transformed_entity)) { - // $entity[$keyval] = $transformed_entity[$key]; - // } elseif (array_key_exists($keyval, $transformed_entity)) { - // $entity[$keyval] = $transformed_entity[$keyval]; - // } - // else { - // $entity[$keyval] = $this->resolveKey($keyval, $task, $this->entity_transformer); - // } } - $entity['start_date'] = ''; - $entity['end_date'] = ''; - $entity['duration'] = ''; + $entity['task.start_date'] = ''; + $entity['task.end_date'] = ''; + $entity['task.duration'] = ''; if (is_null($task->time_log) || (is_array(json_decode($task->time_log, 1)) && count(json_decode($task->time_log, 1)) == 0)) { $this->storage_array[] = $entity; @@ -233,23 +190,23 @@ class TaskExport extends BaseExport $this->storage_array[] = $entity; - unset($entity['start_date']); - unset($entity['end_date']); - unset($entity['duration']); + unset($entity['task.start_date']); + unset($entity['task.end_date']); + unset($entity['task.duration']); } } private function decorateAdvancedFields(Task $task, array $entity) :array { - if (in_array('status_id', $this->input['report_keys'])) { - $entity['status'] = $task->status()->exists() ? $task->status->name : ''; + if (in_array('task.status_id', $this->input['report_keys'])) { + $entity['task.status_id'] = $task->status()->exists() ? $task->status->name : ''; } - if (in_array('project_id', $this->input['report_keys'])) { - $entity['project'] = $task->project()->exists() ? $task->project->name : ''; + if (in_array('task.project_id', $this->input['report_keys'])) { + $entity['task.project_id'] = $task->project()->exists() ? $task->project->name : ''; } - + return $entity; } } diff --git a/app/Export/CSV/VendorExport.php b/app/Export/CSV/VendorExport.php index 011484b054a3..834f73766082 100644 --- a/app/Export/CSV/VendorExport.php +++ b/app/Export/CSV/VendorExport.php @@ -17,6 +17,7 @@ use App\Models\Company; use App\Transformers\VendorContactTransformer; use App\Transformers\VendorTransformer; use App\Utils\Ninja; +use Illuminate\Database\Eloquent\Builder; use Illuminate\Support\Facades\App; use League\Csv\Writer; @@ -31,42 +32,6 @@ class VendorExport extends BaseExport public string $date_key = 'created_at'; - public array $entity_keys = [ - 'address1' => 'vendor.address1', - 'address2' => 'vendor.address2', - 'city' => 'vendor.city', - 'country' => 'vendor.country_id', - 'custom_value1' => 'vendor.custom_value1', - 'custom_value2' => 'vendor.custom_value2', - 'custom_value3' => 'vendor.custom_value3', - 'custom_value4' => 'vendor.custom_value4', - 'id_number' => 'vendor.id_number', - 'name' => 'vendor.name', - 'number' => 'vendor.number', - 'phone' => 'vendor.phone', - 'postal_code' => 'vendor.postal_code', - 'private_notes' => 'vendor.private_notes', - 'public_notes' => 'vendor.public_notes', - 'state' => 'vendor.state', - 'vat_number' => 'vendor.vat_number', - 'website' => 'vendor.website', - 'currency' => 'vendor.currency', - 'first_name' => 'vendor_contact.first_name', - 'last_name' => 'vendor_contact.last_name', - 'contact_phone' => 'vendor_contact.phone', - 'contact_custom_value1' => 'vendor_contact.custom_value1', - 'contact_custom_value2' => 'vendor_contact.custom_value2', - 'contact_custom_value3' => 'vendor_contact.custom_value3', - 'contact_custom_value4' => 'vendor_contact.custom_value4', - 'email' => 'vendor_contact.email', - 'status' => 'vendor.status' - ]; - - private array $decorate_keys = [ - 'vendor.country_id', - 'vendor.currency', - ]; - public function __construct(Company $company, array $input) { $this->company = $company; @@ -75,8 +40,9 @@ class VendorExport extends BaseExport $this->contact_transformer = new VendorContactTransformer(); } - public function run() + public function init(): Builder { + MultiDB::setDb($this->company->db); App::forgetInstance('translator'); App::setLocale($this->company->locale()); @@ -89,17 +55,45 @@ class VendorExport extends BaseExport if (count($this->input['report_keys']) == 0) { $this->input['report_keys'] = array_values($this->entity_keys); } - - //insert the header - $this->csv->insertOne($this->buildHeader()); - + $query = Vendor::query()->with('contacts') - ->withTrashed() - ->where('company_id', $this->company->id) - ->where('is_deleted', 0); + ->withTrashed() + ->where('company_id', $this->company->id) + ->where('is_deleted', 0); $query = $this->addDateRange($query); + return $query; + + } + + public function returnJson() + { + $query = $this->init(); + + $headerdisplay = $this->buildHeader(); + + $header = collect($this->input['report_keys'])->map(function ($key, $value) use($headerdisplay){ + return ['identifier' => $value, 'display_value' => $headerdisplay[$value]]; + })->toArray(); + + $report = $query->cursor() + ->map(function ($resource) { + $row = $this->buildRow($resource); + return $this->processMetaData($row, $resource); + })->toArray(); + + return array_merge(['columns' => $header], $report); + } + + public function run() + { + + $query = $this->init(); + + //insert the header + $this->csv->insertOne($this->buildHeader()); + $query->cursor() ->each(function ($vendor) { $this->csv->insertOne($this->buildRow($vendor)); @@ -123,14 +117,12 @@ class VendorExport extends BaseExport foreach (array_values($this->input['report_keys']) as $key) { $parts = explode('.', $key); - $keyval = array_search($key, $this->entity_keys); - if (is_array($parts) && $parts[0] == 'vendor' && array_key_exists($parts[1], $transformed_vendor)) { - $entity[$keyval] = $transformed_vendor[$parts[1]]; + $entity[$key] = $transformed_vendor[$parts[1]]; } elseif (is_array($parts) && $parts[0] == 'vendor_contact' && array_key_exists($parts[1], $transformed_contact)) { - $entity[$keyval] = $transformed_contact[$parts[1]]; + $entity[$key] = $transformed_contact[$parts[1]]; } else { - $entity[$keyval] = ''; + $entity[$key] = $this->resolveKey($key, $vendor, $this->vendor_transformer); } } diff --git a/app/Http/Controllers/Reports/VendorReportController.php b/app/Http/Controllers/Reports/VendorReportController.php index 2494daadb923..bfd0f3b2298e 100644 --- a/app/Http/Controllers/Reports/VendorReportController.php +++ b/app/Http/Controllers/Reports/VendorReportController.php @@ -11,11 +11,12 @@ namespace App\Http\Controllers\Reports; +use App\Utils\Traits\MakesHash; use App\Export\CSV\VendorExport; +use App\Jobs\Report\SendToAdmin; +use App\Jobs\Report\PreviewReport; use App\Http\Controllers\BaseController; use App\Http\Requests\Report\GenericReportRequest; -use App\Jobs\Report\SendToAdmin; -use App\Utils\Traits\MakesHash; class VendorReportController extends BaseController { @@ -30,14 +31,26 @@ class VendorReportController extends BaseController public function __invoke(GenericReportRequest $request) { + /** @var \App\Models\User $user */ + $user = auth()->user(); + if ($request->has('send_email') && $request->get('send_email')) { - SendToAdmin::dispatch(auth()->user()->company(), $request->all(), VendorExport::class, $this->filename); + SendToAdmin::dispatch($user->company(), $request->all(), VendorExport::class, $this->filename); return response()->json(['message' => 'working...'], 200); } // expect a list of visible fields, or use the default - $export = new VendorExport(auth()->user()->company(), $request->all()); + if($request->has('output') && $request->input('output') == 'json') { + + $hash = \Illuminate\Support\Str::uuid(); + + PreviewReport::dispatch($user->company(), $request->all(), VendorExport::class, $hash); + + return response()->json(['message' => $hash], 200); + } + + $export = new VendorExport($user->company(), $request->all()); $csv = $export->run(); From f67c3cf038bf5eacb53a906b985152af8a39aeb9 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Tue, 12 Sep 2023 14:21:42 +1000 Subject: [PATCH 15/20] Report exports --- app/Export/CSV/BaseExport.php | 2 + app/Export/CSV/VendorExport.php | 4 +- resources/views/react/head.blade.php | 458 +++++++++--------- .../Export/ReportCsvGenerationTest.php | 20 +- 4 files changed, 243 insertions(+), 241 deletions(-) diff --git a/app/Export/CSV/BaseExport.php b/app/Export/CSV/BaseExport.php index 698752b08f79..783a52f3dc55 100644 --- a/app/Export/CSV/BaseExport.php +++ b/app/Export/CSV/BaseExport.php @@ -1092,6 +1092,8 @@ class BaseExport } + nlog($clean_row); + return $clean_row; } diff --git a/app/Export/CSV/VendorExport.php b/app/Export/CSV/VendorExport.php index 834f73766082..4a3c6fad5979 100644 --- a/app/Export/CSV/VendorExport.php +++ b/app/Export/CSV/VendorExport.php @@ -53,7 +53,7 @@ class VendorExport extends BaseExport $this->csv = Writer::createFromString(); if (count($this->input['report_keys']) == 0) { - $this->input['report_keys'] = array_values($this->entity_keys); + $this->input['report_keys'] = array_values($this->vendor_report_keys); } $query = Vendor::query()->with('contacts') @@ -104,7 +104,7 @@ class VendorExport extends BaseExport private function buildRow(Vendor $vendor) :array { - $transformed_contact = []; + $transformed_contact = false; $transformed_vendor = $this->vendor_transformer->transform($vendor); diff --git a/resources/views/react/head.blade.php b/resources/views/react/head.blade.php index fc645e62d397..2a14ac4fa27e 100644 --- a/resources/views/react/head.blade.php +++ b/resources/views/react/head.blade.php @@ -1,235 +1,235 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/Feature/Export/ReportCsvGenerationTest.php b/tests/Feature/Export/ReportCsvGenerationTest.php index 730f8697cbf1..a4a4b200aa0c 100644 --- a/tests/Feature/Export/ReportCsvGenerationTest.php +++ b/tests/Feature/Export/ReportCsvGenerationTest.php @@ -294,16 +294,16 @@ class ReportCsvGenerationTest extends TestCase $csv = $response->streamedContent(); - $this->assertEquals('Vendor 1', $this->getFirstValueByColumn($csv, 'Name')); - $this->assertEquals('1234', $this->getFirstValueByColumn($csv, 'Number')); - $this->assertEquals('city', $this->getFirstValueByColumn($csv, 'City')); - $this->assertEquals('address1', $this->getFirstValueByColumn($csv, 'Street')); - $this->assertEquals('address2', $this->getFirstValueByColumn($csv, 'Apt/Suite')); - $this->assertEquals('postal_code', $this->getFirstValueByColumn($csv, 'Postal Code')); - $this->assertEquals('work_phone', $this->getFirstValueByColumn($csv, 'Phone')); - $this->assertEquals('private_notes', $this->getFirstValueByColumn($csv, 'Private Notes')); - $this->assertEquals('public_notes', $this->getFirstValueByColumn($csv, 'Public Notes')); - $this->assertEquals('website', $this->getFirstValueByColumn($csv, 'Website')); + $this->assertEquals('Vendor 1', $this->getFirstValueByColumn($csv, 'Vendor Name')); + $this->assertEquals('1234', $this->getFirstValueByColumn($csv, 'Vendor Number')); + $this->assertEquals('city', $this->getFirstValueByColumn($csv, 'Vendor City')); + $this->assertEquals('address1', $this->getFirstValueByColumn($csv, 'Vendor Street')); + $this->assertEquals('address2', $this->getFirstValueByColumn($csv, 'Vendor Apt/Suite')); + $this->assertEquals('postal_code', $this->getFirstValueByColumn($csv, 'Vendor Postal Code')); + $this->assertEquals('work_phone', $this->getFirstValueByColumn($csv, 'Vendor Phone')); + $this->assertEquals('private_notes', $this->getFirstValueByColumn($csv, 'Vendor Private Notes')); + $this->assertEquals('public_notes', $this->getFirstValueByColumn($csv, 'Vendor Public Notes')); + $this->assertEquals('website', $this->getFirstValueByColumn($csv, 'Vendor Website')); } From 3cab690af4763217c83e5740a77ec6e43e410905 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Tue, 12 Sep 2023 17:06:40 +1000 Subject: [PATCH 16/20] Fixes for large discounts --- app/Helpers/Invoice/InvoiceItemSum.php | 25 +++++++++++++++++++++---- app/Helpers/Invoice/InvoiceSum.php | 15 ++------------- 2 files changed, 23 insertions(+), 17 deletions(-) diff --git a/app/Helpers/Invoice/InvoiceItemSum.php b/app/Helpers/Invoice/InvoiceItemSum.php index 57d26d43b9cf..ce651f0997c3 100644 --- a/app/Helpers/Invoice/InvoiceItemSum.php +++ b/app/Helpers/Invoice/InvoiceItemSum.php @@ -391,15 +391,21 @@ class InvoiceItemSum { $this->setGroupedTaxes(collect([])); - $item_tax = 0; + - foreach ($this->line_items as $this->item) { + foreach ($this->line_items as $key => $this->item) { if ($this->item->line_total == 0) { continue; } + + $item_tax = 0; //$amount = $this->item->line_total - ($this->item->line_total * ($this->invoice->discount / $this->sub_total)); - $amount = ($this->sub_total > 0) ? $this->item->line_total - ($this->item->line_total * ($this->invoice->discount / $this->sub_total)) : 0; + $amount = ($this->sub_total > 0) ? $this->item->line_total - ($this->invoice->discount * ( $this->item->line_total / $this->sub_total)) : 0; + + nlog("amount discount tax calcs : {$this->item->line_total} - {$this->sub_total} {$amount} {$this->item->line_total} {$this->invoice->discount} / {$this->sub_total}"); + nlog(( $this->item->line_total / $this->sub_total)); + nlog(($this->invoice->discount * ( $this->item->line_total / $this->sub_total))); $item_tax_rate1_total = $this->calcAmountLineTax($this->item->tax_rate1, $amount); @@ -424,9 +430,20 @@ class InvoiceItemSum if ($item_tax_rate3_total != 0) { $this->groupTax($this->item->tax_name3, $this->item->tax_rate3, $item_tax_rate3_total); } + + $this->item->gross_line_total = $this->getLineTotal() + $item_tax; + $this->item->tax_amount = $item_tax; + + $this->line_items[$key] = $this->item; + nlog("amount discount tax calcs : {$this->getLineTotal()} {$this->sub_total} {$amount} {$item_tax} {$this->item->gross_line_total} "); + + $this->setTotalTaxes($this->getTotalTaxes() + $item_tax); + } - $this->setTotalTaxes($item_tax); + + + return $this; } /** diff --git a/app/Helpers/Invoice/InvoiceSum.php b/app/Helpers/Invoice/InvoiceSum.php index 16687aed0298..3f32ed486f78 100644 --- a/app/Helpers/Invoice/InvoiceSum.php +++ b/app/Helpers/Invoice/InvoiceSum.php @@ -308,8 +308,9 @@ class InvoiceSum public function setTaxMap(): self { - if ($this->invoice->is_amount_discount == true) { + if ($this->invoice->is_amount_discount) { $this->invoice_items->calcTaxesWithAmountDiscount(); + $this->invoice->line_items = $this->invoice_items->getLineItems(); } $this->tax_map = collect(); @@ -327,8 +328,6 @@ class InvoiceSum return $value['key'] == $key; })->sum('total'); - //$total_line_tax -= $this->discount($total_line_tax); - $this->tax_map[] = ['name' => $tax_name, 'total' => $total_line_tax]; $this->total_taxes += $total_line_tax; @@ -377,16 +376,6 @@ class InvoiceSum public function purgeTaxes(): self { - // $this->tax_rate1 = 0; - // $this->tax_name1 = ''; - - // $this->tax_rate2 = 0; - // $this->tax_name2 = ''; - - // $this->tax_rate3 = 0; - // $this->tax_name3 = ''; - - // $this->discount = 0; $line_items = collect($this->invoice->line_items); From dc4ccd57cad67bb3669e050fbc6984bf0bac6855 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Tue, 12 Sep 2023 17:07:39 +1000 Subject: [PATCH 17/20] Comment Cleanup --- app/Helpers/Invoice/InvoiceItemSum.php | 5 ----- 1 file changed, 5 deletions(-) diff --git a/app/Helpers/Invoice/InvoiceItemSum.php b/app/Helpers/Invoice/InvoiceItemSum.php index ce651f0997c3..bc368e5f7fa5 100644 --- a/app/Helpers/Invoice/InvoiceItemSum.php +++ b/app/Helpers/Invoice/InvoiceItemSum.php @@ -403,10 +403,6 @@ class InvoiceItemSum //$amount = $this->item->line_total - ($this->item->line_total * ($this->invoice->discount / $this->sub_total)); $amount = ($this->sub_total > 0) ? $this->item->line_total - ($this->invoice->discount * ( $this->item->line_total / $this->sub_total)) : 0; - nlog("amount discount tax calcs : {$this->item->line_total} - {$this->sub_total} {$amount} {$this->item->line_total} {$this->invoice->discount} / {$this->sub_total}"); - nlog(( $this->item->line_total / $this->sub_total)); - nlog(($this->invoice->discount * ( $this->item->line_total / $this->sub_total))); - $item_tax_rate1_total = $this->calcAmountLineTax($this->item->tax_rate1, $amount); $item_tax += $item_tax_rate1_total; @@ -435,7 +431,6 @@ class InvoiceItemSum $this->item->tax_amount = $item_tax; $this->line_items[$key] = $this->item; - nlog("amount discount tax calcs : {$this->getLineTotal()} {$this->sub_total} {$amount} {$item_tax} {$this->item->gross_line_total} "); $this->setTotalTaxes($this->getTotalTaxes() + $item_tax); From 56744fc78cf66c8aa5609ad52fd7449aa3f91a80 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Tue, 12 Sep 2023 17:23:52 +1000 Subject: [PATCH 18/20] Fixes for tests --- app/Export/CSV/BaseExport.php | 4 ++-- app/Export/CSV/VendorExport.php | 2 +- tests/Feature/Export/ReportCsvGenerationTest.php | 8 ++++---- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/app/Export/CSV/BaseExport.php b/app/Export/CSV/BaseExport.php index 783a52f3dc55..21ccedac0b14 100644 --- a/app/Export/CSV/BaseExport.php +++ b/app/Export/CSV/BaseExport.php @@ -65,7 +65,7 @@ class BaseExport 'id_number' => 'vendor.id_number', 'name' => 'vendor.name', 'number' => 'vendor.number', - 'client_phone' => 'vendor.phone', + 'phone' => 'vendor.phone', 'postal_code' => 'vendor.postal_code', 'private_notes' => 'vendor.private_notes', 'public_notes' => 'vendor.public_notes', @@ -657,7 +657,7 @@ class BaseExport // nlog("searching for {$column}"); $transformed_invoice = false; - if($transformer instanceof PaymentTransformer && ($entity->invoice ?? false)) { + if($transformer instanceof PaymentTransformer && ($entity->invoices ?? false)) { $transformed_invoices = $transformer->includeInvoices($entity); $manager = new Manager(); diff --git a/app/Export/CSV/VendorExport.php b/app/Export/CSV/VendorExport.php index 4a3c6fad5979..7f35f96e5425 100644 --- a/app/Export/CSV/VendorExport.php +++ b/app/Export/CSV/VendorExport.php @@ -119,7 +119,7 @@ class VendorExport extends BaseExport if (is_array($parts) && $parts[0] == 'vendor' && array_key_exists($parts[1], $transformed_vendor)) { $entity[$key] = $transformed_vendor[$parts[1]]; - } elseif (is_array($parts) && $parts[0] == 'vendor_contact' && array_key_exists($parts[1], $transformed_contact)) { + } elseif (is_array($parts) && $parts[0] == 'vendor_contact' && isset($transformed_contact[$parts[1]])) { $entity[$key] = $transformed_contact[$parts[1]]; } else { $entity[$key] = $this->resolveKey($key, $vendor, $this->vendor_transformer); diff --git a/tests/Feature/Export/ReportCsvGenerationTest.php b/tests/Feature/Export/ReportCsvGenerationTest.php index a4a4b200aa0c..f7224d9aa43a 100644 --- a/tests/Feature/Export/ReportCsvGenerationTest.php +++ b/tests/Feature/Export/ReportCsvGenerationTest.php @@ -293,7 +293,7 @@ class ReportCsvGenerationTest extends TestCase ])->post('/api/v1/reports/vendors', $data); $csv = $response->streamedContent(); - +nlog($csv); $this->assertEquals('Vendor 1', $this->getFirstValueByColumn($csv, 'Vendor Name')); $this->assertEquals('1234', $this->getFirstValueByColumn($csv, 'Vendor Number')); $this->assertEquals('city', $this->getFirstValueByColumn($csv, 'Vendor City')); @@ -345,9 +345,9 @@ class ReportCsvGenerationTest extends TestCase $csv = $response->streamedContent(); - $this->assertEquals('Vendor 1', $this->getFirstValueByColumn($csv, 'Name')); - $this->assertEquals('1234', $this->getFirstValueByColumn($csv, 'Number')); - $this->assertEquals('city', $this->getFirstValueByColumn($csv, 'City')); + $this->assertEquals('Vendor 1', $this->getFirstValueByColumn($csv, 'Vendor Name')); + $this->assertEquals('1234', $this->getFirstValueByColumn($csv, 'Vendor Number')); + $this->assertEquals('city', $this->getFirstValueByColumn($csv, 'Vendor City')); } From 161e2aeec817c4ca8c802fd1593e46dff3ea9ad1 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Tue, 12 Sep 2023 19:37:28 +1000 Subject: [PATCH 19/20] Tests for gross line totals --- tests/Unit/InvoiceTest.php | 52 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/tests/Unit/InvoiceTest.php b/tests/Unit/InvoiceTest.php index 305e1e86704d..49abb228a8e9 100644 --- a/tests/Unit/InvoiceTest.php +++ b/tests/Unit/InvoiceTest.php @@ -49,6 +49,58 @@ class InvoiceTest extends TestCase $this->invoice_calc = new InvoiceSum($this->invoice); } +public function testGrossTaxAmountCalcuations() + { + $invoice = InvoiceFactory::create($this->company->id, $this->user->id); + $invoice->client_id = $this->client->id; + $invoice->uses_inclusive_taxes = false; + $invoice->discount = 14191; + $invoice->is_amount_discount = true; + $invoice->status_id = 2; + $line_items = []; + + $line_item = new InvoiceItem; + $line_item->quantity = 1; + $line_item->cost = 8000; + $line_item->tax_rate1 = 5; + $line_item->tax_name1 = 'CA'; + $line_item->product_key = 'line1'; + $line_item->notes = 'Test'; + $line_item->tax_id = 1; + $line_items[] = $line_item; + + $line_item = new InvoiceItem; + $line_item->quantity = 1; + $line_item->cost = 9500; + $line_item->tax_rate1 = 5; + $line_item->tax_name1 = 'CA'; + $line_item->product_key = 'line2'; + $line_item->notes = 'Test'; + $line_item->tax_id = 1; + + $line_items[] = $line_item; + + $invoice->line_items = $line_items; + $invoice->save(); + + $calc = $invoice->calc(); + $invoice = $calc->getInvoice(); + + $this->assertEquals(3474.45, $invoice->amount); + $this->assertEquals(14191, $invoice->discount); + $this->assertEquals(165.45, $invoice->total_taxes); + + $item = collect($invoice->line_items)->firstWhere('product_key', 'line1'); + $this->assertEquals(75.63, $item->tax_amount); + $this->assertEquals(8075.63, $item->gross_line_total); + + $item = collect($invoice->line_items)->firstWhere('product_key', 'line2'); + $this->assertEquals(89.82, $item->tax_amount); + $this->assertEquals(9589.82, $item->gross_line_total); + + + } + public function testTaskRoundingPrecisionThree() { $invoice = InvoiceFactory::create($this->company->id, $this->user->id); From b6ffae72a580c2291ebc9fabc8e94b77e95569b1 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Tue, 12 Sep 2023 19:51:49 +1000 Subject: [PATCH 20/20] Updates for search --- app/Http/Controllers/SearchController.php | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/app/Http/Controllers/SearchController.php b/app/Http/Controllers/SearchController.php index ca694e6103ab..fba7c9529439 100644 --- a/app/Http/Controllers/SearchController.php +++ b/app/Http/Controllers/SearchController.php @@ -46,7 +46,8 @@ class SearchController extends Controller 'name' => $client->present()->name(), 'type' => '/client', 'id' => $client->hashed_id, - 'path' => "/clients/{$client->hashed_id}/edit" + 'path' => "/clients/{$client->hashed_id}/edit", + 'heading' => ctrans('texts.clients') ]; }); } @@ -65,7 +66,8 @@ class SearchController extends Controller 'name' => $contact->present()->search_display(), 'type' => '/client_contact', 'id' => $contact->client->hashed_id, - 'path' => "/clients/{$contact->client->hashed_id}" + 'path' => "/clients/{$contact->client->hashed_id}", + 'heading' => ctrans('texts.contacts') ]; }); } @@ -84,7 +86,8 @@ class SearchController extends Controller 'name' => $invoice->client->present()->name() . ' - ' . $invoice->number, 'type' => '/invoice', 'id' => $invoice->hashed_id, - 'path' => "/clients/{$invoice->hashed_id}/edit" + 'path' => "/clients/{$invoice->hashed_id}/edit", + 'heading' => ctrans('texts.invoices') ]; }); } @@ -179,6 +182,7 @@ class SearchController extends Controller 'path' => $value, 'type' => $transkey, 'name' => $translation, + 'heading' => ctrans('texts.settings') ]; }