From 03b5846d8212c11d7fe5da2f75481469196553cb Mon Sep 17 00:00:00 2001 From: Bryce Covert Date: Sat, 23 Jul 2022 09:45:13 -0700 Subject: [PATCH] fixed excel import --- src/cljs/auto_ap/forms/builder.cljs | 18 +- .../views/components/number_filter.cljs | 5 - .../views/pages/admin/excel_import.cljs | 287 ++++++++---------- 3 files changed, 141 insertions(+), 169 deletions(-) diff --git a/src/cljs/auto_ap/forms/builder.cljs b/src/cljs/auto_ap/forms/builder.cljs index 3263bc25..6fac1bcc 100644 --- a/src/cljs/auto_ap/forms/builder.cljs +++ b/src/cljs/auto_ap/forms/builder.cljs @@ -270,8 +270,18 @@ (not can-submit))}]]))) (defn error-notification [] - (consume Consumer ["error"] - (fn [error] - (when error + (consume Consumer ["error" "status"] + (fn [error status] + (println status) + (cond error ^{:key error} - [:div.has-text-danger.animated.fadeInUp {} error])))) + [:div.has-text-danger.animated.fadeInUp {} error] + + (-> status :error first :message) + [:div.has-text-danger.animated.fadeInUp {} (-> status :error first :message)] + + (-> status :error) + [:div.has-text-danger.animated.fadeInUp {} (-> status :error str)] + + :else + nil)))) diff --git a/src/cljs/auto_ap/views/components/number_filter.cljs b/src/cljs/auto_ap/views/components/number_filter.cljs index 3ce3740b..a4dc993c 100644 --- a/src/cljs/auto_ap/views/components/number_filter.cljs +++ b/src/cljs/auto_ap/views/components/number_filter.cljs @@ -3,11 +3,6 @@ [auto-ap.views.utils :refer [bind-field]] [re-frame.core :as re-frame])) -(defn dispatch-change [on-change-event start end] - (fn [_] - (re-frame/dispatch (into on-change-event [[:start] start]) ) - (re-frame/dispatch (into on-change-event [[:end] end])))) - (defn number-filter [{:keys [value on-change-event]}] [:div.field [:div.control diff --git a/src/cljs/auto_ap/views/pages/admin/excel_import.cljs b/src/cljs/auto_ap/views/pages/admin/excel_import.cljs index 380f067e..7f80638f 100644 --- a/src/cljs/auto_ap/views/pages/admin/excel_import.cljs +++ b/src/cljs/auto_ap/views/pages/admin/excel_import.cljs @@ -1,168 +1,115 @@ (ns auto-ap.views.pages.admin.excel-import - (:require [auto-ap.events :as all-events] - [auto-ap.forms :as forms] - [auto-ap.subs :as subs] - [auto-ap.views.components.admin.side-bar :refer [admin-side-bar]] - [auto-ap.views.components.layouts :refer [side-bar-layout]] - [auto-ap.views.components.typeahead :refer [typeahead-v3]] - [auto-ap.views.utils :refer [bind-field dispatch-event]] - [re-frame.core :as re-frame])) - -(re-frame/reg-sub - ::excel-import - (fn [db] - (::excel-import db))) - -(re-frame/reg-sub - ::expense-accounts - (fn [db] - (::expense-accounts db))) - -(re-frame/reg-event-db - ::change - (fn [db [_ field v]] - (assoc-in db (into [::excel-import] field) v))) - - + (:require + [auto-ap.forms :as forms] + [auto-ap.forms.builder :as form-builder] + [auto-ap.schema :as schema] + [auto-ap.views.components :as com] + [auto-ap.views.components.admin.side-bar :refer [admin-side-bar]] + [auto-ap.views.components.layouts :refer [side-bar-layout]] + [auto-ap.views.utils :refer [with-user]] + [malli.core :as m] + [re-frame.core :as re-frame] + [reagent.core :as r])) (re-frame/reg-event-fx ::save - [(forms/in-form ::excel-import)] - (fn [{{excel-import-data :data :as excel-import-form} :db}] - (let [user @(re-frame/subscribe [::subs/token])] - {:db (-> excel-import-form - (assoc :status :loading) - (assoc :error nil)) - :http {:token user - :method :post - :body (pr-str excel-import-data) - :headers {"Content-Type" "application/edn"} - :uri (str "/api/invoices/upload-integreat") - :on-success [::save-complete] - :on-error [::forms/save-error ::excel-import]}}))) + [ with-user (forms/in-form ::form)] + (fn [{:keys [db user]}] + { + :http {:token user + :method :post + :body (pr-str {:excel-rows (:excel-rows (:data db))}) + :headers {"Content-Type" "application/edn"} + :uri (str "/api/invoices/upload-integreat") + :owns-state {:single ::form} + :on-success [::save-complete]}})) (re-frame/reg-event-fx ::save-complete (fn [{:keys [db]} [_ rows]] - {:db - (-> db - (forms/save-succeeded ::excel-import) - (assoc-in [::excel-import :rows] rows))})) + (cond-> + {:db (assoc db ::result rows)} + (seq (:vendors-not-found rows)) (assoc :dispatch [::forms/start-form ::create-vendors ])))) + +(re-frame/reg-sub + ::result + (fn [db] + (::result db))) -(re-frame/reg-event-fx - ::save-error - (fn [{:keys [db]}] - (println "ERROR") - {:dispatch [::change [:error] true] - :db (-> db - (assoc-in [::excel-import :rows] nil) - (assoc-in [::excel-import :saving?] false))})) -(re-frame/reg-event-db - ::toggle-vendor - (fn [db [_ data]] - (update-in db [::excel-import :create-vendors] (fn [x] - (let [x (or x #{})] - (if (x data) - (disj x data) - (conj x data))))))) (re-frame/reg-event-fx ::create-vendors - (fn [{:keys [db]}] - (let [excel-import (::excel-import db)] - (println (::expense-accounts db)) - {:graphql {:token (:user db) - :query-obj {:venia/operation {:operation/type :mutation - :operation/name "UpsertVendor"} - - :venia/queries (map (fn [v ] - {:query/data [:upsert-vendor - {:vendor {:name v :default-account-id (-> db ::expense-accounts (get v) :default-account-id :id)}} - [:id :name]]}) - - (get-in db [::excel-import :create-vendors]))} - :on-success [::create-vendor-complete] - :on-error [::create-vendor-error]} - :db (-> db - (assoc-in [::excel-import :saving-vendors?] true))}))) + [with-user (forms/in-form ::create-vendors)] + (fn [{:keys [user db]}] + {:graphql {:token user + :owns-state {:single ::create-vendors} + :query-obj {:venia/operation {:operation/type :mutation + :operation/name "UpsertVendor"} + + :venia/queries + (for [[vendor-name {:keys [default-account]}] (:data db)] + {:query/data [:upsert-vendor + {:vendor {:name vendor-name :default-account-id (:id default-account)}} + [:id :name]]})} + :on-success [::create-vendor-complete]}})) (re-frame/reg-event-db ::create-vendor-complete - (fn [db [_ data]] - (-> db - (update-in [::excel-import :rows :vendors-not-found] - (fn [v] - (reduce disj v (get-in db [::excel-import :create-vendors])))) - (update-in [::excel-import] dissoc :create-vendors)))) + (fn [db _] + (dissoc db ::result ))) + +(def missing-vendor-schema + (m/schema [:map-of :string + [:map + [:default-account schema/reference]]])) + +(defn create-missing-vendors [{:keys [vendors]}] + (let [{:keys [data]} @(re-frame/subscribe [::forms/form ::create-vendors]) + vendors-to-create (filter (fn [v] (:checked v)) + (vals data))] + [form-builder/builder {:id ::create-vendors + :submit-event [::create-vendors] + :schema missing-vendor-schema} + [:article.message.is-warning.is-paddingless + [:div.message-header + "Some vendors could not be found"] + + [:div.message-body + [:h2 "Check the vendors you want to create"] + (for [v vendors] + ^{:key v} + [:div.field.is-grouped + [:div.control + [form-builder/raw-field-v2 {:field [v :checked]} + [com/checkbox {:label v}]]] + + [:div.control + [form-builder/raw-field-v2 {:field [v :default-account]} + [com/search-backed-typeahead {:search-query (fn [i] + [:search_account + {:query i} + [:name :id :location]])}]]]]) + [form-builder/error-notification] + [form-builder/submit-button {:disabled (when-not (seq vendors-to-create) "disabled")} + (str "Create " (count vendors-to-create) " vendors")] + [:div.is-clearfix]]]])) (defn admin-excel-import-content [] [:div - (let [{{:keys [vendors-not-found already-imported imported]} :rows - :keys [create-vendors] - :or {create-vendors #{}} - :as excel-import-data} @(re-frame/subscribe [::excel-import]) - data @(re-frame/subscribe [::expense-accounts]) - form @(re-frame/subscribe [::forms/form ::excel-import]) - - - chooseable-expense-accounts @(re-frame/subscribe [::subs/all-accounts]) - change-event [::all-events/change-form [::expense-accounts]]] + (let [{:keys [vendors-not-found errors already-imported imported]} @(re-frame/subscribe [::result])] [:div [:h1.title "Import Invoices from Integreat Excel"] (when (seq vendors-not-found) - [:article.message.is-warning.is-paddingless - [:div.message-header - "Some vendors could not be found"] - - [:div.message-body - [:h2 "Check the vendors you want to create"] - [:div.columns - (for [[i vendor-group] (map vector (range) (partition-all (max 1 (/ (count vendors-not-found) 3)) vendors-not-found))] - ^{:key i} - [:div.column - (for [v vendor-group] - ^{:key v} [:div.field.is-grouped - [:p.control - [:label.checkbox - [:input {:value v - :checked (if (create-vendors v) - "checked" - "") - - :type "checkbox" - :on-change (fn [] - (re-frame/dispatch [::toggle-vendor v]))}] - (str " " v)]] - - [:p.control - [bind-field - [typeahead-v3 {:entities chooseable-expense-accounts - :entity->text (fn [x ] (str (:numeric-code x) " - " (:name x))) - :type "typeahead-v3" - :field [v :default-account-id] - :event change-event - :subscription data}]]]])])] - [:div - [:button.button.is-pulled-right - {:on-click (dispatch-event [::create-vendors]) - :disabled (when-not (seq create-vendors) - "disabled") - } - (str "Create " (count create-vendors) " vendors")]] - [:div.is-clearfix]]]) - [bind-field - [:textarea.textarea {:rows "20" - :field :excel-rows - :type "text" - :event [::forms/change ::excel-import] - :subscription (:data form)}]] - - [:button.button.is-large.is-pulled-right.is-primary {:on-click (dispatch-event [::save]) - :class (str @(re-frame/subscribe [::forms/loading-class ::excel-import]) - (when (:error form) " animated shake")) - :disabled (when (= :saving (:status form)) "disabled")} "Import"] - + [create-missing-vendors {:vendors vendors-not-found}] + ) + [form-builder/builder {:id ::form + :submit-event [::save]} + [form-builder/raw-field-v2 {:field :excel-rows} + [:textarea.textarea {:rows "20" + :type "text"}]] + [form-builder/error-notification] + [form-builder/submit-button "Import"]] [:div.is-clearfix] [:div.is-clearfix [:p @@ -171,29 +118,49 @@ [:p (when already-imported (str already-imported " rows already imported."))]] - (when-let [errors (:errors (:rows excel-import-data))] + (when errors [:div [:h3 (str "Import errors (" (min 100 (count errors)) " / " (count errors) " )")] [:table.table.is-fullwidth [:thead - [:th "Date"] - [:th "Invoice #"] - [:th "Client"] - [:th "Vendor"] - [:th "Amount"] - [:th "Errors"]] + [:td "Date"] + [:td "Invoice #"] + [:td "Client"] + [:td "Vendor"] + [:td "Amount"] + [:td "Errors"]] - (for [{:keys [raw-date invoice-number client vendor-name amount] row-errors :errors} (take 100 errors)] - ^{:key (str raw-date invoice-number client vendor-name amount)} - [:tr - [:td raw-date] - [:td invoice-number] - [:td client] - [:td vendor-name] - [:td amount] - [:td (map (fn [{:keys [info]}] ^{:key info} [:p info]) row-errors)]])]])])]) + [:tbody + (for [{:keys [raw-date invoice-number client vendor-name amount] row-errors :errors} (take 100 errors)] + ^{:key (str raw-date invoice-number client vendor-name amount)} + [:tr + [:td raw-date] + [:td invoice-number] + [:td client] + [:td vendor-name] + [:td amount] + [:td (map (fn [{:keys [info]}] ^{:key info} [:p info]) row-errors)]])]]])])]) -(defn admin-excel-import-page [] +(defn admin-excel-import-page-internal [] [side-bar-layout {:side-bar [admin-side-bar {}] :main [admin-excel-import-content]}]) + +(re-frame/reg-event-fx + ::mounted + (fn [_ _] + {:dispatch [::forms/start-form ::form]})) + +(re-frame/reg-event-fx + ::unmounted + (fn [{:keys [db]} _] + {:dispatch-n [[::forms/form-closing ::form] + [::forms/form-closing ::create-vendors]] + :db (dissoc db ::results)})) + +(defn admin-excel-import-page [] + (r/create-class + {:display-name "excel-import-page" + :component-will-unmount #(re-frame/dispatch-sync [::unmounted]) + :component-did-mount #(re-frame/dispatch [::mounted]) + :reagent-render admin-excel-import-page-internal}))