scottohara/loot

View on GitHub
src/transactions/views/edit.html

Summary

Maintainability
Test Coverage
<form role="form" name="transactionForm" autocomplete="off">
    <div class="modal-header">
        <h4>{{::vm.mode}} Transaction</h4>
    </div>
    <div class="modal-body">
        <div
            ng-if="::vm.transaction.status == 'Reconciled' || vm.transaction.related_status == 'Reconciled'"
            class="alert alert-danger"
        >
            <strong>Warning!</strong>
            This transaction has been
            <span ng-if="::vm.transaction.status != 'Reconciled'">partially </span
            >reconciled
        </div>
        <!-- Transaction Date -->
        <div
            class="form-group has-feedback"
            ng-class="{'has-error': transactionForm.transactionDate.$invalid}"
        >
            <label for="transactionDate">Date</label>
            <input
                id="transactionDate"
                name="transactionDate"
                class="form-control"
                type="date"
                ng-model="vm.transaction.transaction_date"
                required
                autofocus
            />
            <span
                ng-show="transactionForm.transactionDate.$invalid"
                class="glyphicon glyphicon-remove form-control-feedback"
            ></span>
        </div>
        <!-- Primary Account -->
        <div
            class="form-group has-feedback"
            ng-class="{'has-error': transactionForm.primaryAccount.$invalid}"
        >
            <label for="primaryAccount">Account</label>
            <input
                name="primaryAccount"
                class="form-control"
                ng-model="vm.transaction.primary_account"
                uib-typeahead="account as account.name for account in vm.accounts($viewValue, 10)"
                ng-blur="vm.primaryAccountSelected()"
                typeahead-editable="false"
                typeahead-select-on-blur="true"
                typeahead-template-url="../../og-components/og-favourite/views/typeahead-suggestion.html"
                placeholder="Account"
                required
                og-input-autoselect
            />
            <span
                ng-show="transactionForm.primaryAccount.$invalid"
                class="glyphicon glyphicon-remove form-control-feedback"
            ></span>
        </div>
        <!-- Payee -->
        <div
            ng-if="vm.transaction.primary_account.account_type != 'investment'"
            class="form-group has-feedback"
            ng-class="{'has-warning': vm.isString(vm.transaction.payee), 'has-error': transactionForm.payee.$invalid}"
        >
            <label for="payee">Payee</label>
            <input
                name="payee"
                class="form-control"
                ng-model="vm.transaction.payee"
                uib-typeahead="payee as payee.name for payee in vm.payees($viewValue, 10)"
                ng-blur="vm.payeeSelected()"
                typeahead-select-on-blur="true"
                typeahead-template-url="../../og-components/og-favourite/views/typeahead-suggestion.html"
                placeholder="Payee"
                required
                og-input-autoselect
            />
            <span
                ng-show="vm.isString(vm.transaction.payee) || transactionForm.payee.$invalid"
                class="glyphicon form-control-feedback"
                ng-class="{'glyphicon-warning-sign': vm.isString(vm.transaction.payee), 'glyphicon-remove': transactionForm.payee.$invalid}"
            ></span>
        </div>
        <!-- Security -->
        <div
            ng-if="vm.transaction.primary_account.account_type == 'investment'"
            class="form-group has-feedback"
            ng-class="{'has-warning': vm.isString(vm.transaction.security), 'has-error': transactionForm.security.$invalid}"
        >
            <label for="security">Security</label>
            <input
                name="security"
                class="form-control"
                ng-model="vm.transaction.security"
                uib-typeahead="security as security.name for security in vm.securities($viewValue, 10)"
                ng-blur="vm.securitySelected()"
                typeahead-select-on-blur="true"
                typeahead-template-url="../../og-components/og-favourite/views/typeahead-suggestion.html"
                placeholder="Security"
                required
                og-input-autoselect
            />
            <span
                ng-show="vm.isString(vm.transaction.security) || transactionForm.security.$invalid"
                class="glyphicon form-control-feedback"
                ng-class="{'glyphicon-warning-sign': vm.isString(vm.transaction.security), 'glyphicon-remove': transactionForm.security.$invalid}"
            ></span>
        </div>
        <!-- Investment Category -->
        <div
            ng-if="vm.transaction.primary_account.account_type == 'investment'"
            class="form-group has-feedback"
            ng-class="{'has-error': transactionForm.category.$invalid}"
        >
            <label for="category">Category</label>
            <input
                id="category"
                name="category"
                class="form-control"
                ng-model="vm.transaction.category"
                uib-typeahead="category as category.name for category in vm.investmentCategories($viewValue)"
                ng-blur="vm.investmentCategorySelected()"
                typeahead-editable="false"
                typeahead-min-length="0"
                typeahead-select-on-blur="true"
                placeholder="Category"
                required
                og-input-autoselect
            />
            <span
                ng-show="transactionForm.category.$invalid"
                class="glyphicon glyphicon-remove form-control-feedback"
            ></span>
        </div>
        <!-- Transaction Amount -->
        <div
            ng-if="vm.transaction.primary_account.account_type != 'investment' || vm.transaction.category.id == 'DividendTo'"
            class="form-group has-feedback"
            ng-class="{'has-error': transactionForm.amount.$invalid}"
        >
            <label for="amount">Amount</label>
            <input
                id="amount"
                name="amount"
                class="form-control"
                ng-class="{'negative': vm.transaction.amount < 0}"
                ng-model="vm.transaction.amount"
                placeholder="Transaction Amount"
                required
                og-input-currency
                og-input-autoselect
                og-input-calculator
            />
            <span
                ng-show="transactionForm.amount.$invalid"
                class="glyphicon glyphicon-remove form-control-feedback"
            ></span>
        </div>
        <!-- Category -->
        <div
            ng-if="vm.transaction.primary_account.account_type != 'investment'"
            class="form-group has-feedback"
            ng-class="{'has-warning': vm.isString(vm.transaction.category), 'has-error': transactionForm.category.$invalid}"
        >
            <label for="category">Category</label>
            <input
                id="category"
                name="category"
                class="form-control"
                ng-model="vm.transaction.category"
                uib-typeahead="category as category.name for category in vm.categories($viewValue, 10, null, true)"
                ng-blur="vm.categorySelected()"
                typeahead-select-on-blur="true"
                typeahead-template-url="../../og-components/og-favourite/views/typeahead-suggestion.html"
                placeholder="Category"
                required
                og-input-autoselect
            />
            <span
                ng-show="vm.isString(vm.transaction.category) || transactionForm.category.$invalid"
                class="glyphicon form-control-feedback"
                ng-class="{'glyphicon-warning-sign': vm.isString(vm.transaction.category), 'glyphicon-remove': transactionForm.category.$invalid}"
            ></span>
        </div>
        <!-- Subcategory -->
        <div
            ng-if="vm.transaction.primary_account.account_type != 'investment' && ['TransferTo', 'TransferFrom', 'SplitTo', 'SplitFrom', 'LoanRepayment', 'Payslip'].indexOf(vm.transaction.category.id) == -1"
            class="form-group has-feedback"
            ng-class="{'has-warning': vm.isString(vm.transaction.subcategory)}"
        >
            <label for="subcategory">Subcategory</label>
            <input
                id="subcategory"
                name="subcategory"
                class="form-control"
                ng-disabled="!(vm.isString(vm.transaction.category) || vm.transaction.category.id > 0)"
                ng-model="vm.transaction.subcategory"
                uib-typeahead="subcategory as subcategory.name for subcategory in vm.categories($viewValue, 10, vm.transaction.category)"
                typeahead-select-on-blur="true"
                typeahead-template-url="../../og-components/og-favourite/views/typeahead-suggestion.html"
                placeholder="Subcategory"
                og-input-autoselect
            />
            <span
                ng-show="vm.isString(vm.transaction.subcategory)"
                class="glyphicon glyphicon-warning-sign form-control-feedback"
            ></span>
        </div>
        <!-- Account -->
        <div
            ng-if="['TransferTo', 'TransferFrom', 'Buy', 'Sell', 'DividendTo'].indexOf(vm.transaction.category.id) != -1"
            class="form-group has-feedback"
            ng-class="{'has-error': transactionForm.account.$invalid}"
        >
            <label for="account">Account</label>
            <input
                id="account"
                name="account"
                class="form-control"
                ng-model="vm.transaction.account"
                uib-typeahead="account as account.name for account in vm.accounts($viewValue, 10)"
                typeahead-editable="false"
                typeahead-select-on-blur="true"
                typeahead-template-url="../../og-components/og-favourite/views/typeahead-suggestion.html"
                placeholder="Account"
                required
                og-input-autoselect
            />
            <span
                ng-show="transactionForm.account.$invalid"
                class="glyphicon glyphicon-remove form-control-feedback"
            ></span>
        </div>
        <!-- Quantity -->
        <div
            ng-if="vm.transaction.primary_account.account_type == 'investment' && ['TransferTo', 'TransferFrom', 'AddShares', 'RemoveShares', 'Buy', 'Sell'].indexOf(vm.transaction.category.id) != -1"
            class="form-group has-feedback"
            ng-class="{'has-error': transactionForm.quantity.$invalid}"
        >
            <label for="quantity">Quantity</label>
            <input
                id="quantity"
                name="quantity"
                class="form-control"
                ng-class="{'negative': vm.transaction.quantity < 0}"
                ng-model="vm.transaction.quantity"
                ng-change="vm.updateInvestmentDetails()"
                placeholder="Quantity"
                required
                og-input-number
                og-input-autoselect
                og-input-calculator
            />
            <span
                ng-show="transactionForm.quantity.$invalid"
                class="glyphicon glyphicon-remove form-control-feedback"
            ></span>
        </div>
        <!-- Price -->
        <div
            ng-if="vm.transaction.primary_account.account_type == 'investment' && ['Buy', 'Sell'].indexOf(vm.transaction.category.id) != -1"
            class="form-group has-feedback"
            ng-class="{'has-error': transactionForm.price.$invalid}"
        >
            <label for="price">Price</label>
            <input
                id="price"
                name="price"
                class="form-control"
                ng-class="{'negative': vm.transaction.price < 0}"
                ng-model="vm.transaction.price"
                ng-change="vm.updateInvestmentDetails()"
                placeholder="Price"
                required
                og-input-currency="3"
                og-input-autoselect
                og-input-calculator
            />
            <span
                ng-show="transactionForm.price.$invalid"
                class="glyphicon glyphicon-remove form-control-feedback"
            ></span>
        </div>
        <!-- Commission -->
        <div
            ng-if="vm.transaction.primary_account.account_type == 'investment' && ['Buy', 'Sell'].indexOf(vm.transaction.category.id) != -1"
            class="form-group has-feedback"
            ng-class="{'has-error': transactionForm.commission.$invalid}"
        >
            <label for="commission">Commission</label>
            <input
                id="commission"
                name="commission"
                class="form-control"
                ng-class="{'negative': vm.transaction.commission < 0}"
                ng-model="vm.transaction.commission"
                ng-change="vm.updateInvestmentDetails()"
                placeholder="Commission"
                required
                og-input-currency
                og-input-autoselect
                og-input-calculator
            />
            <span
                ng-show="transactionForm.commission.$invalid"
                class="glyphicon glyphicon-remove form-control-feedback"
            ></span>
        </div>
        <!-- Investment Amount -->
        <div
            ng-if="vm.transaction.primary_account.account_type == 'investment' && ['Buy', 'Sell'].indexOf(vm.transaction.category.id) != -1"
            class="form-group"
        >
            <label>Amount</label>
            <div ng-class="{'text-danger': vm.transaction.amount < 0}">
                {{vm.transaction.amount | currency}}
            </div>
        </div>
        <!-- Subtransactions -->
        <div
            ng-if="['SplitTo', 'SplitFrom', 'LoanRepayment', 'Payslip'].indexOf(vm.transaction.category.id) != -1"
        >
            <table class="table table-condensed">
                <thead>
                    <tr>
                        <th>Category</th>
                        <th>Subcategory</th>
                        <th>Memo</th>
                        <th>Amount</th>
                        <th></th>
                    </tr>
                </thead>
                <tbody>
                    <tr ng-repeat="subtransaction in vm.transaction.subtransactions">
                        <td>
                            <!-- Category -->
                            <ng-form name="categoryForm">
                                <div class="form-inline">
                                    <div
                                        class="form-group has-feedback"
                                        ng-class="{'has-warning': vm.isString(subtransaction.category), 'has-error': categoryForm.category.$invalid}"
                                    >
                                        <input
                                            name="category"
                                            class="form-control"
                                            ng-model="subtransaction.category"
                                            uib-typeahead="category as category.name for category in vm.categories($viewValue, 10)"
                                            ng-blur="vm.categorySelected($index)"
                                            typeahead-select-on-blur="true"
                                            typeahead-template-url="../../og-components/og-favourite/views/typeahead-suggestion.html"
                                            placeholder="Category"
                                            required
                                            og-input-autoselect
                                        />
                                        <span
                                            ng-show="vm.isString(subtransaction.category) || categoryForm.category.$invalid"
                                            class="glyphicon form-control-feedback"
                                            ng-class="{'glyphicon-warning-sign': vm.isString(subtransaction.category), 'glyphicon-remove': categoryForm.category.$invalid}"
                                        ></span>
                                    </div>
                                </div>
                            </ng-form>
                        </td>
                        <td
                            ng-switch="['TransferTo', 'TransferFrom'].indexOf(subtransaction.category.id)"
                        >
                            <ng-form name="accountForm">
                                <div class="form-inline">
                                    <!-- Subcategory -->
                                    <div
                                        ng-switch-when="-1"
                                        class="form-group has-feedback"
                                        ng-class="{'has-warning': vm.isString(subtransaction.subcategory)}"
                                    >
                                        <input
                                            class="form-control"
                                            ng-disabled="!(vm.isString(subtransaction.category) || subtransaction.category.id > 0)"
                                            ng-model="subtransaction.subcategory"
                                            uib-typeahead="subcategory as subcategory.name for subcategory in vm.categories($viewValue, 10, subtransaction.category)"
                                            typeahead-select-on-blur="true"
                                            typeahead-template-url="../../og-components/og-favourite/views/typeahead-suggestion.html"
                                            placeholder="Subcategory"
                                            og-input-autoselect
                                        />
                                        <span
                                            ng-show="vm.isString(subtransaction.subcategory)"
                                            class="glyphicon glyphicon-warning-sign form-control-feedback"
                                        ></span>
                                    </div>
                                    <!-- Account -->
                                    <div
                                        ng-switch-default
                                        class="form-group has-feedback"
                                        ng-class="{'has-error': accountForm.account.$invalid}"
                                    >
                                        <input
                                            name="account"
                                            class="form-control"
                                            ng-model="subtransaction.account"
                                            uib-typeahead="account as account.name for account in vm.accounts($viewValue, 10)"
                                            typeahead-editable="false"
                                            typeahead-select-on-blur="true"
                                            typeahead-template-url="../../og-components/og-favourite/views/typeahead-suggestion.html"
                                            placeholder="Account"
                                            required
                                            og-input-autoselect
                                        />
                                        <span
                                            ng-show="accountForm.account.$invalid"
                                            class="glyphicon glyphicon-remove form-control-feedback"
                                        ></span>
                                    </div>
                                </div>
                            </ng-form>
                        </td>
                        <td>
                            <!-- Memo -->
                            <input
                                class="form-control"
                                ng-model="subtransaction.memo"
                                placeholder="Memo"
                                og-input-autoselect
                            />
                        </td>
                        <td>
                            <!-- Amount -->
                            <ng-form name="amountForm">
                                <div class="form-inline">
                                    <div
                                        class="form-group has-feedback has-action"
                                        ng-class="{'has-error': amountForm.amount.$invalid}"
                                    >
                                        <input
                                            name="amount"
                                            class="form-control text-right"
                                            ng-class="{'negative': (subtransaction.amount * (subtransaction.direction == vm.transaction.direction ? 1 : -1)) < 0}"
                                            ng-model="subtransaction.amount"
                                            placeholder="Amount"
                                            required
                                            og-input-currency
                                            og-input-autoselect
                                            og-input-calculator="right"
                                        />
                                        <span
                                            ng-show="amountForm.amount.$invalid"
                                            class="glyphicon glyphicon-remove form-control-feedback"
                                        ></span>
                                        <span
                                            ng-show="!amountForm.amount.$invalid && vm.transaction.amount - vm.totalAllocated !== 0"
                                            class="form-control-feedback"
                                            ><i
                                                class="action glyphicon glyphicon-plus-sign"
                                                uib-tooltip="Add unallocated amount here"
                                                ng-click="vm.addUnallocatedAmount($index)"
                                            ></i
                                        ></span>
                                    </div>
                                </div>
                            </ng-form>
                        </td>
                        <td>
                            <button
                                class="btn btn-default"
                                type="button"
                                ng-click="vm.deleteSubtransaction($index)"
                            >
                                <span class="glyphicon glyphicon-trash"></span>
                            </button>
                        </td>
                    </tr>
                </tbody>
                <tfoot>
                    <tr>
                        <td>
                            <button
                                class="btn btn-xs btn-success"
                                type="button"
                                ng-click="vm.addSubtransaction()"
                            >
                                <span class="glyphicon glyphicon-plus"> Add</span>
                            </button>
                        </td>
                        <td colspan="2" class="text-right">Allocated</td>
                        <td class="text-right">{{vm.totalAllocated | currency}}</td>
                    </tr>
                    <tr>
                        <td
                            colspan="3"
                            class="text-right"
                            ng-class="{'text-danger': vm.transaction.amount - vm.totalAllocated !== 0, 'text-success': vm.transaction.amount - vm.totalAllocated === 0}"
                        >
                            Unallocated
                        </td>
                        <td
                            class="text-right"
                            ng-class="{'text-danger': vm.transaction.amount - vm.totalAllocated !== 0, 'text-success': vm.transaction.amount - vm.totalAllocated === 0}"
                        >
                            {{vm.transaction.amount - vm.totalAllocated | currency}}
                        </td>
                    </tr>
                </tfoot>
            </table>
        </div>
        <!-- Memo -->
        <div class="form-group has-feedback has-action">
            <label for="memo">Memo</label>
            <input
                id="memo"
                name="memo"
                class="form-control"
                ng-model="vm.transaction.memo"
                placeholder="Memo"
                og-input-autoselect
            />
            <span
                ng-show="['SplitTo', 'SplitFrom', 'LoanRepayment', 'Payslip'].indexOf(vm.transaction.category.id) != -1"
                class="form-control-feedback"
            >
                <i
                    class="action glyphicon glyphicon-refresh"
                    uib-tooltip="Use splits"
                    ng-click="vm.memoFromSubtransactions()"
                ></i>
            </span>
        </div>
    </div>
    <div class="modal-footer">
        <span ng-if="vm.errorMessage" class="text-danger">{{vm.errorMessage}}</span>
        <span
            ng-if="vm.loadingLastTransaction"
            class="pull-left text-muted"
            og-loading-spinner="'Finding last transaction for ' + (vm.transaction.payee.name || vm.transaction.security.name)"
        ></span>
        <button class="btn btn-default" type="button" ng-click="vm.cancel()">
            Cancel
        </button>
        <button
            class="btn btn-primary"
            type="submit"
            ng-disabled="transactionForm.$invalid"
            ng-click="vm.save()"
        >
            <i class="glyphicon glyphicon-ok"></i> Save
        </button>
    </div>
</form>