(ns auto-ap.views.components.expense-accounts-dialog (:require [re-frame.core :as re-frame] [reagent.core :as r] [clojure.string :as str] [clojure.spec.alpha :as s] [cljs-time.core :as c] [goog.string :as gstring] [auto-ap.subs :as subs] [auto-ap.entities.clients :as client] [auto-ap.entities.invoice :as invoice] [auto-ap.entities.vendors :as vendor] [auto-ap.expense-accounts :as expense-accounts] [auto-ap.entities.invoices-expense-accounts :as invoices-expense-accounts] [auto-ap.views.components.modal :refer [modal action-modal]] [auto-ap.views.utils :refer [dispatch-event bind-field horizontal-field date->str str->date pretty standard]] [auto-ap.utils :refer [by replace-if]] [auto-ap.views.components.typeahead :refer [typeahead]] [auto-ap.events :as events])) (re-frame/reg-sub ::change-expense-accounts (fn [db] (-> db ::change-expense-accounts))) (re-frame/reg-event-fx ::change-expense-accounts (fn [{:keys [db]} [_ i]] {:dispatch [::events/modal-status ::change-expense-accounts {:visible? true}] :db (assoc-in db [::change-expense-accounts :invoice] i)})) (re-frame/reg-event-fx ::change-expense-accounts-saving (fn [{:keys [db]} [_ on-success id ]] (let [{:keys [id expense-accounts]} (get-in db [::change-expense-accounts :invoice])] {:graphql {:token (-> db :user) :query-obj {:venia/operation {:operation/type :mutation :operation/name "EditExpenseAccounts"} :venia/queries [{:query/data [:edit-expense-accounts {:invoice-id id :expense-accounts (map (fn [ea] {:id (:id ea) :amount (:amount ea) :location (:location ea) :expense-account-id (:expense-account-id ea)}) expense-accounts)} [:id :total :outstanding-balance :invoice-number :date [:vendor [:name :id]] [:expense_accounts [:amount :id :location :expense_account_id [:expense_account [:id :name [:parent [:id :name]]]]]] [:client [:name :id :locations]] [:payments [:amount [:payment [:amount :s3_url :check_number ]]]] ]]}]} :on-success on-success}}))) (re-frame/reg-event-db ::add-expense-account-split (fn [db _] (let [{{{:keys [locations]} :client} :invoice} @(re-frame/subscribe [::change-expense-accounts])] (update-in db [::change-expense-accounts :invoice :expense-accounts] conj {:amount 0 :expense-account-id nil :location (first locations)})))) (re-frame/reg-event-db ::remove-expense-account-split (fn [db [_ index]] (update-in db [::change-expense-accounts :invoice :expense-accounts] (fn [expense-accounts] (vec (concat (take index expense-accounts) (drop (inc index) expense-accounts))))))) (defn change-expense-accounts-modal [{:keys [updated-event]}] (let [{{:keys [expense-accounts total ] :or {expense-accounts [] total 0} {:keys [locations]} :client} :invoice :as data} @(re-frame/subscribe [::change-expense-accounts]) multi-location? (> (count locations) 1) change-event [::events/change-form [::change-expense-accounts]] chooseable-expense-accounts @(re-frame/subscribe [::subs/chooseable-expense-accounts]) expense-accounts-total (->> expense-accounts (map :amount) (map js/parseFloat) (map #(or % 0)) (reduce + 0)) does-add-up? (< (Math/abs (- expense-accounts-total (js/parseFloat total))) 0.01)] [action-modal {:id ::change-expense-accounts :title "Change expense accounts" :action-text "Save" :save-event [::change-expense-accounts-saving updated-event] :can-submit? (and does-add-up? (s/valid? (s/* ::invoices-expense-accounts/invoices-expense-account) expense-accounts))} [:div [:a.button.is-primary {:on-click (dispatch-event [::add-expense-account-split])} "Add split"]] [:table.table [:thead [:tr [:th {:style {:width "500px"}} "Expense Account"] (when multi-location? [:th {:style {:width "200px"}} "Location"]) [:th {:style {:width "300px"}} "Amount"] [:th {:style {:width "5em"}}]]] [:tbody (for [[expense-account index] (map vector expense-accounts (range))] ^{:key index} [:tr [:td.expandable [:div.control [bind-field [typeahead {:matches (map (fn [x] [(:id x) (str (:id x) " - " (:name x))]) chooseable-expense-accounts) :type "typeahead" :field [:invoice :expense-accounts index :expense-account-id] :event change-event :spec ::invoice/vendor-id :subscription data}]]]] (when multi-location? [:td (if-let [forced-location (-> expense-account :expense-account-id expense-accounts/expense-accounts :location)] [:div.select [:select {:disabled "disabled" :value forced-location} [:option {:value forced-location} forced-location]]] [:div.select [bind-field [:select {:type "select" :field [:invoice :expense-accounts index :location] :spec (set locations) :event change-event :subscription data} (map (fn [l] ^{:key l} [:option {:value l} l]) locations)]]])]) [:td [:div.control [:div.field.has-addons.is-extended [:p.control [:a.button.is-static "$"]] [:p.control [bind-field [:input.input {:type "number" :field [:invoice :expense-accounts index :amount] :event change-event :subscription data :value (get-in data [:invoice :expense-accounts index :amount]) :max (:total data) :step "0.01"}]]]]]] [:td [:a.button {:on-click (dispatch-event [::remove-expense-account-split index])} [:i.fa.fa-times]]]] ) [:tr [:th "TOTAL"] [:th (str (gstring/format "$%.2f" expense-accounts-total ) " (" (gstring/format "$%.2f" total ) ")" )]]]]]))