refractor: accounting module (#300)
* Refractor components. * Add resolvers. * Add relative router links. * Replace mat-icons by font-awesome icons. * Add comments. Fixes: #298
This commit is contained in:
+6
-1
@@ -23,7 +23,12 @@
|
|||||||
"selector-class-pattern": "[a-z-]+",
|
"selector-class-pattern": "[a-z-]+",
|
||||||
"selector-id-pattern": "[a-z-]+",
|
"selector-id-pattern": "[a-z-]+",
|
||||||
"selector-max-id": 1,
|
"selector-max-id": 1,
|
||||||
"selector-no-qualifying-type": true,
|
"selector-no-qualifying-type": [
|
||||||
|
true,
|
||||||
|
{
|
||||||
|
"ignore": ["class"]
|
||||||
|
}
|
||||||
|
],
|
||||||
"selector-max-universal": 0,
|
"selector-max-universal": 0,
|
||||||
"selector-type-no-unknown": [
|
"selector-type-no-unknown": [
|
||||||
true,
|
true,
|
||||||
|
|||||||
@@ -1,3 +1,6 @@
|
|||||||
|
/** TODO: Separate routing into feature modules for cleaner accounting module. */
|
||||||
|
|
||||||
|
/** Angular Imports */
|
||||||
import { NgModule } from '@angular/core';
|
import { NgModule } from '@angular/core';
|
||||||
import { Routes, RouterModule } from '@angular/router';
|
import { Routes, RouterModule } from '@angular/router';
|
||||||
|
|
||||||
@@ -7,24 +10,21 @@ import { Route } from '../core/route/route.service';
|
|||||||
/** Translation Imports */
|
/** Translation Imports */
|
||||||
import { extract } from '../core/i18n/i18n.service';
|
import { extract } from '../core/i18n/i18n.service';
|
||||||
|
|
||||||
|
/** Custom Components */
|
||||||
import { AccountingComponent } from './accounting.component';
|
import { AccountingComponent } from './accounting.component';
|
||||||
import { FrequentPostingsComponent } from './frequent-postings/frequent-postings.component';
|
import { FrequentPostingsComponent } from './frequent-postings/frequent-postings.component';
|
||||||
import { ViewTransactionComponent } from './view-transaction/view-transaction.component';
|
|
||||||
import { CreateJournalEntryComponent } from './create-journal-entry/create-journal-entry.component';
|
import { CreateJournalEntryComponent } from './create-journal-entry/create-journal-entry.component';
|
||||||
import { SearchJournalEntryComponent } from './search-journal-entry/search-journal-entry.component';
|
import { SearchJournalEntryComponent } from './search-journal-entry/search-journal-entry.component';
|
||||||
|
import { ViewTransactionComponent } from './view-transaction/view-transaction.component';
|
||||||
import { FinancialActivityMappingsComponent } from './financial-activity-mappings/financial-activity-mappings.component';
|
import { FinancialActivityMappingsComponent } from './financial-activity-mappings/financial-activity-mappings.component';
|
||||||
import { CreateFinancialActivityMappingComponent } from './financial-activity-mappings/create-financial-activity-mapping/create-financial-activity-mapping.component';
|
import { CreateFinancialActivityMappingComponent } from './financial-activity-mappings/create-financial-activity-mapping/create-financial-activity-mapping.component';
|
||||||
import { ViewFinancialActivityMappingComponent } from './financial-activity-mappings/view-financial-activity-mapping/view-financial-activity-mapping.component';
|
import { ViewFinancialActivityMappingComponent } from './financial-activity-mappings/view-financial-activity-mapping/view-financial-activity-mapping.component';
|
||||||
import { EditFinancialActivityMappingComponent } from './financial-activity-mappings/edit-financial-activity-mapping/edit-financial-activity-mapping.component';
|
import { EditFinancialActivityMappingComponent } from './financial-activity-mappings/edit-financial-activity-mapping/edit-financial-activity-mapping.component';
|
||||||
|
import { MigrateOpeningBalancesComponent } from './migrate-opening-balances/migrate-opening-balances.component';
|
||||||
import { ChartOfAccountsComponent } from './chart-of-accounts/chart-of-accounts.component';
|
import { ChartOfAccountsComponent } from './chart-of-accounts/chart-of-accounts.component';
|
||||||
|
|
||||||
import { ChartOfAccountsResolver } from './chart-of-accounts/chart-of-accounts.resolver';
|
|
||||||
|
|
||||||
import { CreateGlAccountComponent } from './chart-of-accounts/create-gl-account/create-gl-account.component';
|
import { CreateGlAccountComponent } from './chart-of-accounts/create-gl-account/create-gl-account.component';
|
||||||
import { ViewGlAccountComponent } from './chart-of-accounts/view-gl-account/view-gl-account.component';
|
import { ViewGlAccountComponent } from './chart-of-accounts/view-gl-account/view-gl-account.component';
|
||||||
import { ViewGlAccountResolver } from './chart-of-accounts/view-gl-account/view-gl-account.resolver';
|
|
||||||
import { EditGlAccountComponent } from './chart-of-accounts/edit-gl-account/edit-gl-account.component';
|
import { EditGlAccountComponent } from './chart-of-accounts/edit-gl-account/edit-gl-account.component';
|
||||||
|
|
||||||
import { ClosingEntriesComponent } from './closing-entries/closing-entries.component';
|
import { ClosingEntriesComponent } from './closing-entries/closing-entries.component';
|
||||||
import { CreateClosureComponent } from './closing-entries/create-closure/create-closure.component';
|
import { CreateClosureComponent } from './closing-entries/create-closure/create-closure.component';
|
||||||
import { ViewClosureComponent } from './closing-entries/view-closure/view-closure.component';
|
import { ViewClosureComponent } from './closing-entries/view-closure/view-closure.component';
|
||||||
@@ -32,15 +32,40 @@ import { EditClosureComponent } from './closing-entries/edit-closure/edit-closur
|
|||||||
import { AccountingRulesComponent } from './accounting-rules/accounting-rules.component';
|
import { AccountingRulesComponent } from './accounting-rules/accounting-rules.component';
|
||||||
import { CreateRuleComponent } from './accounting-rules/create-rule/create-rule.component';
|
import { CreateRuleComponent } from './accounting-rules/create-rule/create-rule.component';
|
||||||
import { ViewRuleComponent } from './accounting-rules/view-rule/view-rule.component';
|
import { ViewRuleComponent } from './accounting-rules/view-rule/view-rule.component';
|
||||||
import { ViewAccountingRuleResolver } from './accounting-rules/view-rule/view-rule.resolver';
|
|
||||||
import { EditRuleComponent } from './accounting-rules/edit-rule/edit-rule.component';
|
import { EditRuleComponent } from './accounting-rules/edit-rule/edit-rule.component';
|
||||||
import { PeriodicAccrualsComponent } from './periodic-accruals/periodic-accruals.component';
|
import { PeriodicAccrualsComponent } from './periodic-accruals/periodic-accruals.component';
|
||||||
import { ProvisioningEntriesComponent } from './provisioning-entries/provisioning-entries.component';
|
import { ProvisioningEntriesComponent } from './provisioning-entries/provisioning-entries.component';
|
||||||
import { CreateProvisioningEntryComponent } from './provisioning-entries/create-provisioning-entry/create-provisioning-entry.component';
|
import { CreateProvisioningEntryComponent } from './provisioning-entries/create-provisioning-entry/create-provisioning-entry.component';
|
||||||
import { ViewProvisioningEntryComponent } from './provisioning-entries/view-provisioning-entry/view-provisioning-entry.component';
|
import { ViewProvisioningEntryComponent } from './provisioning-entries/view-provisioning-entry/view-provisioning-entry.component';
|
||||||
import { ViewProvisioningJournalEntriesComponent } from './provisioning-entries/view-provisioning-journal-entries/view-provisioning-journal-entries.component';
|
import { ViewProvisioningJournalEntriesComponent } from './provisioning-entries/view-provisioning-journal-entries/view-provisioning-journal-entries.component';
|
||||||
import { MigrateOpeningBalancesComponent } from './migrate-opening-balances/migrate-opening-balances.component';
|
|
||||||
|
|
||||||
|
/** Custom Resolvers */
|
||||||
|
import { OfficesResolver } from './common-resolvers/offices.resolver';
|
||||||
|
import { AccountingRulesAssociationsResolver } from './common-resolvers/accounting-rules-associations.resolver';
|
||||||
|
import { CurrenciesResolver } from './common-resolvers/currencies.resolver';
|
||||||
|
import { PaymentTypesResolver } from './common-resolvers/payment-types.resolver';
|
||||||
|
import { GlAccountsResolver } from './common-resolvers/gl-accounts.resolver';
|
||||||
|
import { TransactionResolver } from './view-transaction/transaction.resolver';
|
||||||
|
import { FinancialActivityMappingsResolver } from './financial-activity-mappings/financial-activity-mappings.resolver';
|
||||||
|
import { FinancialActivityMappingsTemplateResolver } from './financial-activity-mappings/create-financial-activity-mapping/financial-activity-mappings-template.resolver';
|
||||||
|
import { FinancialActivityMappingResolver } from './financial-activity-mappings/view-financial-activity-mapping/financial-activity-mapping.resolver';
|
||||||
|
import { FinancialActivityMappingAndTemplateResolver } from './financial-activity-mappings/edit-financial-activity-mapping/financial-activity-mapping-and-template.resolver';
|
||||||
|
import { ChartOfAccountsResolver } from './chart-of-accounts/chart-of-accounts.resolver';
|
||||||
|
import { ChartOfAccountsTemplateResolver } from './chart-of-accounts/create-gl-account/chart-of-accounts-template.resolver';
|
||||||
|
import { GlAccountAndChartOfAccountsTemplateResolver } from './chart-of-accounts/gl-account-and-chart-of-accounts-template.resolver';
|
||||||
|
import { ClosingEntriesResolver } from './closing-entries/closing-entries.resolver';
|
||||||
|
import { ClosingEntryResolver } from './closing-entries/closing-entry.resolver';
|
||||||
|
import { AccountingRulesResolver } from './accounting-rules/accounting-rules.resolver';
|
||||||
|
import { AccountingRulesTemplateResolver } from './accounting-rules/accounting-rules-template.resolver';
|
||||||
|
import { AccountingRuleResolver } from './accounting-rules/accounting-rule.resolver';
|
||||||
|
import { ProvisioningEntriesResolver } from './provisioning-entries/provisioning-entries.resolver';
|
||||||
|
import { ProvisioningEntryResolver } from './provisioning-entries/view-provisioning-entry/provisioning-entry.resolver';
|
||||||
|
import { ProvisioningEntryEntriesResolver } from './provisioning-entries/view-provisioning-entry/provisioning-entry-entries.resolver';
|
||||||
|
import { LoanProductsResolver } from './common-resolvers/loan-products.resolver';
|
||||||
|
import { ProvisioningCategoriesResolver } from './common-resolvers/provisioning-categories.resolver';
|
||||||
|
import { ProvisioningJournalEntriesResolver } from './provisioning-entries/view-provisioning-journal-entries/provisioning-journal-entries.resolver';
|
||||||
|
|
||||||
|
/** Accounting Routes */
|
||||||
const routes: Routes = [
|
const routes: Routes = [
|
||||||
Route.withShell([
|
Route.withShell([
|
||||||
{
|
{
|
||||||
@@ -52,43 +77,73 @@ const routes: Routes = [
|
|||||||
component: AccountingComponent
|
component: AccountingComponent
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: 'frequent-postings',
|
path: 'journal-entries',
|
||||||
component: FrequentPostingsComponent,
|
data: { title: extract('Search Journal Entry'), breadcrumb: 'Journal Entries' },
|
||||||
data: { title: extract('Frequent Postings'), breadcrumb: 'Frequent Postings' }
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: 'transactions',
|
|
||||||
data: { title: extract('Transactions'), breadcrumb: 'Transactions' },
|
|
||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
path: 'view/:id',
|
path: '',
|
||||||
component: ViewTransactionComponent,
|
component: SearchJournalEntryComponent,
|
||||||
data: { title: extract('View Transaction'), routeParamBreadcrumb: 'id' }
|
resolve: {
|
||||||
}
|
offices: OfficesResolver,
|
||||||
|
glAccounts: GlAccountsResolver
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'frequent-postings',
|
||||||
|
component: FrequentPostingsComponent,
|
||||||
|
data: { title: extract('Frequent Postings'), breadcrumb: 'Frequent Postings' },
|
||||||
|
resolve: {
|
||||||
|
offices: OfficesResolver,
|
||||||
|
accountingRules: AccountingRulesAssociationsResolver,
|
||||||
|
currencies: CurrenciesResolver,
|
||||||
|
paymentTypes: PaymentTypesResolver
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'create',
|
||||||
|
component: CreateJournalEntryComponent,
|
||||||
|
data: { title: extract('Create Journal Entry'), breadcrumb: 'Create' },
|
||||||
|
resolve: {
|
||||||
|
offices: OfficesResolver,
|
||||||
|
currencies: CurrenciesResolver,
|
||||||
|
paymentTypes: PaymentTypesResolver,
|
||||||
|
glAccounts: GlAccountsResolver
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'transactions',
|
||||||
|
data: { title: extract('Transactions'), breadcrumb: 'Transactions', addBreadcrumbLink: false },
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
path: 'view/:id',
|
||||||
|
component: ViewTransactionComponent,
|
||||||
|
data: { title: extract('View Transaction'), routeParamBreadcrumb: 'id' },
|
||||||
|
resolve: {
|
||||||
|
transaction: TransactionResolver
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
|
||||||
path: 'journal-entries',
|
|
||||||
component: SearchJournalEntryComponent,
|
|
||||||
data: { title: extract('Search Journal Entry'), breadcrumb: 'Search Journal Entry' }
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: 'journal-entries/create',
|
|
||||||
component: CreateJournalEntryComponent,
|
|
||||||
data: { title: extract('Create Journal Entry'), breadcrumb: 'Create Journal Entry' }
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
path: 'financial-activity-mappings',
|
path: 'financial-activity-mappings',
|
||||||
data: { title: extract('Financial Activity Mappings'), breadcrumb: 'Financial Activity Mappings' },
|
data: { title: extract('Financial Activity Mappings'), breadcrumb: 'Financial Activity Mappings' },
|
||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
path: '',
|
path: '',
|
||||||
component: FinancialActivityMappingsComponent
|
component: FinancialActivityMappingsComponent,
|
||||||
|
resolve: {
|
||||||
|
financialActivityAccounts: FinancialActivityMappingsResolver
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: 'create',
|
path: 'create',
|
||||||
component: CreateFinancialActivityMappingComponent,
|
component: CreateFinancialActivityMappingComponent,
|
||||||
data: { title: extract('Create Financial Activity Mapping'), breadcrumb: 'Create' },
|
data: { title: extract('Create Financial Activity Mapping'), breadcrumb: 'Create' },
|
||||||
|
resolve: {
|
||||||
|
financialActivityAccountsTemplate: FinancialActivityMappingsTemplateResolver
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: 'view/:id',
|
path: 'view/:id',
|
||||||
@@ -96,52 +151,72 @@ const routes: Routes = [
|
|||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
path: '',
|
path: '',
|
||||||
component: ViewFinancialActivityMappingComponent
|
component: ViewFinancialActivityMappingComponent,
|
||||||
|
resolve: {
|
||||||
|
financialActivityAccount: FinancialActivityMappingResolver
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: 'edit',
|
path: 'edit',
|
||||||
component: EditFinancialActivityMappingComponent,
|
component: EditFinancialActivityMappingComponent,
|
||||||
data: { title: extract('Edit Financial Activity Mapping'), breadcrumb: 'Edit', routeParamBreadcrumb: false }
|
data: { title: extract('Edit Financial Activity Mapping'), breadcrumb: 'Edit', routeParamBreadcrumb: false },
|
||||||
|
resolve: {
|
||||||
|
financialActivityAccountAndTemplate: FinancialActivityMappingAndTemplateResolver
|
||||||
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: 'migrate-opening-balances',
|
||||||
|
component: MigrateOpeningBalancesComponent,
|
||||||
|
data: { title: extract('Migrate Opening Balances'), breadcrumb: 'Migrate Opening Balances' },
|
||||||
|
resolve: {
|
||||||
|
offices: OfficesResolver,
|
||||||
|
currencies: CurrenciesResolver
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
path: 'chart-of-accounts',
|
path: 'chart-of-accounts',
|
||||||
data: { title: extract('Chart of Accounts'), breadcrumb: 'Chart of Accounts' },
|
data: { title: extract('Chart of Accounts'), breadcrumb: 'Chart of Accounts' },
|
||||||
resolve: {
|
|
||||||
glAccountData: ChartOfAccountsResolver
|
|
||||||
},
|
|
||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
path: '',
|
path: '',
|
||||||
component: ChartOfAccountsComponent,
|
component: ChartOfAccountsComponent,
|
||||||
resolve: {
|
resolve: {
|
||||||
glAccountData: ChartOfAccountsResolver
|
chartOfAccounts: ChartOfAccountsResolver
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: 'gl-accounts/create',
|
path: 'gl-accounts',
|
||||||
component: CreateGlAccountComponent,
|
|
||||||
data: { title: extract('Create GL Account'), breadcrumb: 'Create GL Account' },
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: 'gl-accounts/view/:id',
|
|
||||||
data: { title: extract('View GL Account'), routeResolveBreadcrumb: ['glAccount', 'name'] },
|
|
||||||
resolve: {
|
|
||||||
glAccount: ViewGlAccountResolver
|
|
||||||
},
|
|
||||||
runGuardsAndResolvers: 'always',
|
|
||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
path: '',
|
path: 'create',
|
||||||
component: ViewGlAccountComponent
|
component: CreateGlAccountComponent,
|
||||||
|
data: { title: extract('Create GL Account'), breadcrumb: 'Create GL Account' },
|
||||||
|
resolve: {
|
||||||
|
chartOfAccountsTemplate: ChartOfAccountsTemplateResolver
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: 'edit',
|
path: 'view/:id',
|
||||||
component: EditGlAccountComponent,
|
data: { title: extract('View GL Account'), routeResolveBreadcrumb: ['glAccountAndChartOfAccountsTemplate', 'name'] },
|
||||||
data: { title: extract('Edit GL Account'), breadcrumb: 'Edit', routeResolveBreadcrumb: false }
|
resolve: {
|
||||||
|
glAccountAndChartOfAccountsTemplate: GlAccountAndChartOfAccountsTemplateResolver
|
||||||
|
},
|
||||||
|
runGuardsAndResolvers: 'always',
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
path: '',
|
||||||
|
component: ViewGlAccountComponent
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'edit',
|
||||||
|
component: EditGlAccountComponent,
|
||||||
|
data: { title: extract('Edit GL Account'), breadcrumb: 'Edit', routeResolveBreadcrumb: false }
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -153,16 +228,27 @@ const routes: Routes = [
|
|||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
path: '',
|
path: '',
|
||||||
component: ClosingEntriesComponent
|
component: ClosingEntriesComponent,
|
||||||
|
resolve: {
|
||||||
|
offices: OfficesResolver,
|
||||||
|
glAccountClosures: ClosingEntriesResolver
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: 'create',
|
path: 'create',
|
||||||
component: CreateClosureComponent,
|
component: CreateClosureComponent,
|
||||||
data: { title: extract('Create Accounting Closure'), breadcrumb: 'Create' }
|
data: { title: extract('Create Accounting Closure'), breadcrumb: 'Create' },
|
||||||
|
resolve: {
|
||||||
|
offices: OfficesResolver
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: 'view/:id',
|
path: 'view/:id',
|
||||||
data: { title: extract('View Accounting Closure'), routeParamBreadcrumb: 'id' },
|
data: { title: extract('View Accounting Closure'), routeParamBreadcrumb: 'id' },
|
||||||
|
resolve: {
|
||||||
|
glAccountClosure: ClosingEntryResolver
|
||||||
|
},
|
||||||
|
runGuardsAndResolvers: 'always',
|
||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
path: '',
|
path: '',
|
||||||
@@ -183,18 +269,24 @@ const routes: Routes = [
|
|||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
path: '',
|
path: '',
|
||||||
component: AccountingRulesComponent
|
component: AccountingRulesComponent,
|
||||||
|
resolve: {
|
||||||
|
accountingRules: AccountingRulesResolver
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: 'create',
|
path: 'create',
|
||||||
component: CreateRuleComponent,
|
component: CreateRuleComponent,
|
||||||
data: { title: extract('Create Accounting Rule'), breadcrumb: 'Create' }
|
data: { title: extract('Create Accounting Rule'), breadcrumb: 'Create' },
|
||||||
|
resolve: {
|
||||||
|
accountingRulesTemplate: AccountingRulesTemplateResolver
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: 'view/:id',
|
path: 'view/:id',
|
||||||
data: { title: extract('View Accounting Rule'), routeResolveBreadcrumb: ['accountingRule', 'name'] },
|
data: { title: extract('View Accounting Rule'), routeResolveBreadcrumb: ['accountingRule', 'name'] },
|
||||||
resolve: {
|
resolve: {
|
||||||
accountingRule: ViewAccountingRuleResolver
|
accountingRule: AccountingRuleResolver
|
||||||
},
|
},
|
||||||
runGuardsAndResolvers: 'always',
|
runGuardsAndResolvers: 'always',
|
||||||
children: [
|
children: [
|
||||||
@@ -205,7 +297,10 @@ const routes: Routes = [
|
|||||||
{
|
{
|
||||||
path: 'edit',
|
path: 'edit',
|
||||||
component: EditRuleComponent,
|
component: EditRuleComponent,
|
||||||
data: { title: extract('Edit Accounting Rules'), breadcrumb: 'Edit', routeResolveBreadcrumb: false }
|
data: { title: extract('Edit Accounting Rules'), breadcrumb: 'Edit', routeResolveBreadcrumb: false },
|
||||||
|
resolve: {
|
||||||
|
accountingRulesTemplate: AccountingRulesTemplateResolver
|
||||||
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -222,7 +317,10 @@ const routes: Routes = [
|
|||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
path: '',
|
path: '',
|
||||||
component: ProvisioningEntriesComponent
|
component: ProvisioningEntriesComponent,
|
||||||
|
resolve: {
|
||||||
|
provisioningEntries: ProvisioningEntriesResolver
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: 'create',
|
path: 'create',
|
||||||
@@ -232,38 +330,69 @@ const routes: Routes = [
|
|||||||
{
|
{
|
||||||
path: 'view/:id',
|
path: 'view/:id',
|
||||||
component: ViewProvisioningEntryComponent,
|
component: ViewProvisioningEntryComponent,
|
||||||
data: { title: extract('View Provisioning Entry'), routeParamBreadcrumb: 'id' }
|
data: { title: extract('View Provisioning Entry'), routeParamBreadcrumb: 'id' },
|
||||||
|
resolve: {
|
||||||
|
provisioningEntry: ProvisioningEntryResolver,
|
||||||
|
provisioningEntryEntries: ProvisioningEntryEntriesResolver,
|
||||||
|
office: OfficesResolver,
|
||||||
|
loanProducts: LoanProductsResolver,
|
||||||
|
provisioningCategories: ProvisioningCategoriesResolver
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: 'journal-entries',
|
path: 'journal-entries',
|
||||||
data: { title: extract('View Provisioning Journal Entry'), breadcrumb: 'Journal Entries', addBreadcrumbLink: false },
|
data: { breadcrumb: 'Journal Entries', addBreadcrumbLink: false },
|
||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
path: 'view/:id',
|
path: 'view/:id',
|
||||||
component: ViewProvisioningJournalEntriesComponent,
|
component: ViewProvisioningJournalEntriesComponent,
|
||||||
data: { title: extract('View Provisioning Journal Entry'), routeParamBreadcrumb: 'id' }
|
data: { title: extract('View Provisioning Journal Entry'), routeParamBreadcrumb: 'id' },
|
||||||
|
resolve: {
|
||||||
|
provisioningJournalEntries: ProvisioningJournalEntriesResolver
|
||||||
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
|
||||||
{
|
|
||||||
path: 'migrate-opening-balances',
|
|
||||||
component: MigrateOpeningBalancesComponent,
|
|
||||||
data: { title: extract('Migrate Opening Balances'), breadcrumb: 'Migrate Opening Balances' }
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
])
|
])
|
||||||
];
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Accounting Routing Module
|
||||||
|
*
|
||||||
|
* Configures the accounting routes.
|
||||||
|
*/
|
||||||
@NgModule({
|
@NgModule({
|
||||||
imports: [RouterModule.forChild(routes)],
|
imports: [RouterModule.forChild(routes)],
|
||||||
exports: [RouterModule],
|
exports: [RouterModule],
|
||||||
providers: [
|
providers: [
|
||||||
|
OfficesResolver,
|
||||||
|
AccountingRulesAssociationsResolver,
|
||||||
|
CurrenciesResolver,
|
||||||
|
PaymentTypesResolver,
|
||||||
|
GlAccountsResolver,
|
||||||
|
TransactionResolver,
|
||||||
|
FinancialActivityMappingsResolver,
|
||||||
|
FinancialActivityMappingsTemplateResolver,
|
||||||
|
FinancialActivityMappingResolver,
|
||||||
|
FinancialActivityMappingAndTemplateResolver,
|
||||||
ChartOfAccountsResolver,
|
ChartOfAccountsResolver,
|
||||||
ViewGlAccountResolver,
|
ChartOfAccountsTemplateResolver,
|
||||||
ViewAccountingRuleResolver
|
GlAccountAndChartOfAccountsTemplateResolver,
|
||||||
|
ClosingEntriesResolver,
|
||||||
|
ClosingEntryResolver,
|
||||||
|
AccountingRulesResolver,
|
||||||
|
AccountingRulesTemplateResolver,
|
||||||
|
AccountingRuleResolver,
|
||||||
|
ProvisioningEntriesResolver,
|
||||||
|
ProvisioningEntryResolver,
|
||||||
|
ProvisioningEntryEntriesResolver,
|
||||||
|
LoanProductsResolver,
|
||||||
|
ProvisioningCategoriesResolver,
|
||||||
|
ProvisioningJournalEntriesResolver
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
export class AccountingRoutingModule { }
|
export class AccountingRoutingModule { }
|
||||||
|
|||||||
@@ -0,0 +1,31 @@
|
|||||||
|
/** Angular Imports */
|
||||||
|
import { Injectable } from '@angular/core';
|
||||||
|
import { Resolve, ActivatedRouteSnapshot } from '@angular/router';
|
||||||
|
|
||||||
|
/** rxjs Imports */
|
||||||
|
import { Observable } from 'rxjs';
|
||||||
|
|
||||||
|
/** Custom Services */
|
||||||
|
import { AccountingService } from '../accounting.service';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Accounting rule data resolver.
|
||||||
|
*/
|
||||||
|
@Injectable()
|
||||||
|
export class AccountingRuleResolver implements Resolve<Object> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {AccountingService} accountingService Accounting service.
|
||||||
|
*/
|
||||||
|
constructor(private accountingService: AccountingService) {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the accounting rule data.
|
||||||
|
* @returns {Observable<any>}
|
||||||
|
*/
|
||||||
|
resolve(route: ActivatedRouteSnapshot): Observable<any> {
|
||||||
|
const id = route.paramMap.get('id');
|
||||||
|
return this.accountingService.getAccountingRule(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
/** Angular Imports */
|
||||||
|
import { Injectable } from '@angular/core';
|
||||||
|
import { Resolve } from '@angular/router';
|
||||||
|
|
||||||
|
/** rxjs Imports */
|
||||||
|
import { Observable } from 'rxjs';
|
||||||
|
|
||||||
|
/** Custom Services */
|
||||||
|
import { AccountingService } from '../accounting.service';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Accounting rules template data resolver.
|
||||||
|
*/
|
||||||
|
@Injectable()
|
||||||
|
export class AccountingRulesTemplateResolver implements Resolve<Object> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {AccountingService} accountingService Accounting service.
|
||||||
|
*/
|
||||||
|
constructor(private accountingService: AccountingService) {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the accounting rules template data.
|
||||||
|
* @returns {Observable<any>}
|
||||||
|
*/
|
||||||
|
resolve(): Observable<any> {
|
||||||
|
return this.accountingService.getAccountingRulesTemplate();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,14 +1,16 @@
|
|||||||
<div class="container m-b-20" fxLayout="row" fxLayoutAlign="end" fxLayoutGap="20px">
|
<div class="container m-b-20" fxLayout="row" fxLayoutAlign="end" fxLayoutGap="20px">
|
||||||
<button mat-raised-button color="primary" [routerLink]="['/accounting/accounting-rules/create']">
|
<button mat-raised-button color="primary" [routerLink]="['create']">
|
||||||
<mat-icon>add</mat-icon> Add Rule
|
<fa-icon icon="plus"></fa-icon>
|
||||||
|
Add Rule
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="container">
|
<div class="container">
|
||||||
|
|
||||||
<div fxLayout="row" fxLayoutGap="20px">
|
<div fxLayout="row">
|
||||||
<mat-form-field fxFlex>
|
<mat-form-field fxFlex>
|
||||||
<input matInput (keyup)="applyFilter($event.target.value)" placeholder="Filter">
|
<mat-label>Filter</mat-label>
|
||||||
|
<input matInput (keyup)="applyFilter($event.target.value)">
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -47,7 +49,7 @@
|
|||||||
</ng-container>
|
</ng-container>
|
||||||
|
|
||||||
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
|
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
|
||||||
<tr mat-row *matRowDef="let row; columns: displayedColumns;" [routerLink]="['/accounting/accounting-rules/view', row.id]"></tr>
|
<tr mat-row *matRowDef="let row; columns: displayedColumns;" [routerLink]="['view', row.id]" class="select-row"></tr>
|
||||||
|
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,7 @@
|
|||||||
table {
|
table {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
|
||||||
|
.select-row:hover {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,11 @@
|
|||||||
|
/** Angular Imports */
|
||||||
import { Component, OnInit, ViewChild } from '@angular/core';
|
import { Component, OnInit, ViewChild } from '@angular/core';
|
||||||
import { MatPaginator, MatSort, MatTableDataSource } from '@angular/material';
|
import { MatPaginator, MatSort, MatTableDataSource } from '@angular/material';
|
||||||
import { AccountingService } from '../accounting.service';
|
import { ActivatedRoute } from '@angular/router';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Accounting rules component.
|
||||||
|
*/
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'mifosx-accounting-rules',
|
selector: 'mifosx-accounting-rules',
|
||||||
templateUrl: './accounting-rules.component.html',
|
templateUrl: './accounting-rules.component.html',
|
||||||
@@ -9,37 +13,59 @@ import { AccountingService } from '../accounting.service';
|
|||||||
})
|
})
|
||||||
export class AccountingRulesComponent implements OnInit {
|
export class AccountingRulesComponent implements OnInit {
|
||||||
|
|
||||||
|
/** Accounting rule data. */
|
||||||
|
accountingRuleData: any;
|
||||||
|
/** Columns to be displayed in accounting rules table. */
|
||||||
displayedColumns: string[] = ['name', 'officeName', 'debitTags', 'debitAccount', 'creditTags', 'creditAccount'];
|
displayedColumns: string[] = ['name', 'officeName', 'debitTags', 'debitAccount', 'creditTags', 'creditAccount'];
|
||||||
dataSource: any;
|
/** Data source for accounting rules table. */
|
||||||
|
dataSource: MatTableDataSource<any>;
|
||||||
|
|
||||||
|
/** Paginator for accounting rules table. */
|
||||||
@ViewChild(MatPaginator) paginator: MatPaginator;
|
@ViewChild(MatPaginator) paginator: MatPaginator;
|
||||||
|
/** Sorter for accounting rules table. */
|
||||||
@ViewChild(MatSort) sort: MatSort;
|
@ViewChild(MatSort) sort: MatSort;
|
||||||
|
|
||||||
constructor(private accountingService: AccountingService) { }
|
/**
|
||||||
|
* Retrieves the accounting rules data from `resolve`.
|
||||||
ngOnInit() {
|
* @param {ActivatedRoute} route Activated Route.
|
||||||
this.getAccountingRules();
|
*/
|
||||||
}
|
constructor(private route: ActivatedRoute) {
|
||||||
|
this.route.data.subscribe((data: { accountingRules: any }) => {
|
||||||
getAccountingRules() {
|
this.accountingRuleData = data.accountingRules;
|
||||||
this.accountingService.getAccountingRules().subscribe(accountingRules => {
|
|
||||||
accountingRules.forEach((accountingRule: any) => {
|
|
||||||
accountingRule.debitTags = accountingRule.debitTags ? accountingRule.debitTags.map((debitTag: any) => debitTag.tag.name).join(', ') : '';
|
|
||||||
accountingRule.creditTags = accountingRule.creditTags ? accountingRule.creditTags.map((creditTag: any) => creditTag.tag.name).join(', ') : '';
|
|
||||||
});
|
|
||||||
this.dataSource = new MatTableDataSource(accountingRules);
|
|
||||||
this.dataSource.paginator = this.paginator;
|
|
||||||
this.dataSource.sortingDataAccessor = (accountingRule: any, property: any) => {
|
|
||||||
switch (property) {
|
|
||||||
case 'debitAccount': return accountingRule.debitAccounts[0].name;
|
|
||||||
case 'creditAccount': return accountingRule.creditAccounts[0].name;
|
|
||||||
default: return accountingRule[property];
|
|
||||||
}
|
|
||||||
};
|
|
||||||
this.dataSource.sort = this.sort;
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the accounting rules table.
|
||||||
|
*/
|
||||||
|
ngOnInit() {
|
||||||
|
this.setAccountingRules();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes the data source, paginator and sorter for accounting rules table.
|
||||||
|
*/
|
||||||
|
setAccountingRules() {
|
||||||
|
this.accountingRuleData.forEach((accountingRule: any) => {
|
||||||
|
accountingRule.debitTags = accountingRule.debitTags ? accountingRule.debitTags.map((debitTag: any) => debitTag.tag.name).join(', ') : '';
|
||||||
|
accountingRule.creditTags = accountingRule.creditTags ? accountingRule.creditTags.map((creditTag: any) => creditTag.tag.name).join(', ') : '';
|
||||||
|
});
|
||||||
|
this.dataSource = new MatTableDataSource(this.accountingRuleData);
|
||||||
|
this.dataSource.paginator = this.paginator;
|
||||||
|
this.dataSource.sortingDataAccessor = (accountingRule: any, property: any) => {
|
||||||
|
switch (property) {
|
||||||
|
case 'debitAccount': return accountingRule.debitAccounts[0].name;
|
||||||
|
case 'creditAccount': return accountingRule.creditAccounts[0].name;
|
||||||
|
default: return accountingRule[property];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
this.dataSource.sort = this.sort;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Filters data in accounting rules table based on passed value.
|
||||||
|
* @param {string} filterValue Value to filter data.
|
||||||
|
*/
|
||||||
applyFilter(filterValue: string) {
|
applyFilter(filterValue: string) {
|
||||||
this.dataSource.filter = filterValue.trim().toLowerCase();
|
this.dataSource.filter = filterValue.trim().toLowerCase();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,30 @@
|
|||||||
|
/** Angular Imports */
|
||||||
|
import { Injectable } from '@angular/core';
|
||||||
|
import { Resolve } from '@angular/router';
|
||||||
|
|
||||||
|
/** rxjs Imports */
|
||||||
|
import { Observable } from 'rxjs';
|
||||||
|
|
||||||
|
/** Custom Services */
|
||||||
|
import { AccountingService } from '../accounting.service';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Accounting rules data resolver.
|
||||||
|
*/
|
||||||
|
@Injectable()
|
||||||
|
export class AccountingRulesResolver implements Resolve<Object> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {AccountingService} accountingService Accounting service.
|
||||||
|
*/
|
||||||
|
constructor(private accountingService: AccountingService) {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the accounting rules data.
|
||||||
|
* @returns {Observable<any>}
|
||||||
|
*/
|
||||||
|
resolve(): Observable<any> {
|
||||||
|
return this.accountingService.getAccountingRules();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -9,19 +9,27 @@
|
|||||||
<div fxLayout="row wrap" fxLayoutGap="2%" fxLayout.lt-md="column">
|
<div fxLayout="row wrap" fxLayoutGap="2%" fxLayout.lt-md="column">
|
||||||
|
|
||||||
<mat-form-field fxFlex="48%">
|
<mat-form-field fxFlex="48%">
|
||||||
<input matInput placeholder="Accounting Rule Name" required formControlName="name">
|
<mat-label>Accounting Rule Name</mat-label>
|
||||||
|
<input matInput required formControlName="name">
|
||||||
|
<mat-error *ngIf="accountingRuleForm.controls.name.hasError('required')">
|
||||||
|
Accounting Rule Name is <strong>required</strong>
|
||||||
|
</mat-error>
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
|
|
||||||
<mat-form-field fxFlex="48%">
|
<mat-form-field fxFlex="48%">
|
||||||
<mat-select placeholder="Office" required formControlName="officeId">
|
<mat-label>Office</mat-label>
|
||||||
|
<mat-select required formControlName="officeId">
|
||||||
<mat-option *ngFor="let office of officeData" [value]="office.id">
|
<mat-option *ngFor="let office of officeData" [value]="office.id">
|
||||||
{{ office.name }}
|
{{ office.name }}
|
||||||
</mat-option>
|
</mat-option>
|
||||||
</mat-select>
|
</mat-select>
|
||||||
|
<mat-error *ngIf="accountingRuleForm.controls.officeId.hasError('required')">
|
||||||
|
Office is <strong>required</strong>
|
||||||
|
</mat-error>
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
|
|
||||||
<div fxFlex="48%" fxLayout="row" fxLayout.lt-md="column" class="rule-wrapper">
|
<div fxFlex="48%" fxLayout="row" fxLayout.lt-md="column" class="rule-wrapper">
|
||||||
<label fxFlex="50%">Affected GL Entry (Debit) Rule Type *</label>
|
<mat-label fxFlex="50%">Affected GL Entry (Debit) Rule Type *</mat-label>
|
||||||
<mat-radio-group fxFlex="50%" fxLayout="row" fxLayoutGap="5%" formControlName="debitRuleType">
|
<mat-radio-group fxFlex="50%" fxLayout="row" fxLayoutGap="5%" formControlName="debitRuleType">
|
||||||
<mat-radio-button value="fixedAccount">Fixed Account</mat-radio-button>
|
<mat-radio-button value="fixedAccount">Fixed Account</mat-radio-button>
|
||||||
<mat-radio-button value="listOfAccounts">List of Accounts</mat-radio-button>
|
<mat-radio-button value="listOfAccounts">List of Accounts</mat-radio-button>
|
||||||
@@ -29,7 +37,8 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<mat-form-field fxFlex="48%" *ngIf="accountingRuleForm.controls.debitRuleType.value === 'fixedAccount'">
|
<mat-form-field fxFlex="48%" *ngIf="accountingRuleForm.controls.debitRuleType.value === 'fixedAccount'">
|
||||||
<mat-select placeholder="Account to Debit" required formControlName="accountToDebit">
|
<mat-label>Account to Debit</mat-label>
|
||||||
|
<mat-select formControlName="accountToDebit">
|
||||||
<mat-option *ngFor="let glAccount of glAccountData" [value]="glAccount.id">
|
<mat-option *ngFor="let glAccount of glAccountData" [value]="glAccount.id">
|
||||||
{{ glAccount.name }}
|
{{ glAccount.name }}
|
||||||
</mat-option>
|
</mat-option>
|
||||||
@@ -38,22 +47,23 @@
|
|||||||
|
|
||||||
<div fxFlex="48%" fxLayout="row" fxLayoutGap="2%" fxLayout.lt-md="column" *ngIf="accountingRuleForm.controls.debitRuleType.value === 'listOfAccounts'">
|
<div fxFlex="48%" fxLayout="row" fxLayoutGap="2%" fxLayout.lt-md="column" *ngIf="accountingRuleForm.controls.debitRuleType.value === 'listOfAccounts'">
|
||||||
<mat-form-field fxFlex="50%">
|
<mat-form-field fxFlex="50%">
|
||||||
<mat-select placeholder="Debit Tags" required formControlName="debitTags" multiple>
|
<mat-label>Debit Tags</mat-label>
|
||||||
|
<mat-select formControlName="debitTags" multiple>
|
||||||
<mat-option *ngFor="let debitTag of debitTagData" [value]="debitTag.id">
|
<mat-option *ngFor="let debitTag of debitTagData" [value]="debitTag.id">
|
||||||
{{ debitTag.name }}
|
{{ debitTag.name }}
|
||||||
</mat-option>
|
</mat-option>
|
||||||
</mat-select>
|
</mat-select>
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
|
|
||||||
<div fxFlex="50%" class="entries-wrapper">
|
<div fxFlex="50%" ngClass.gt-md="entries-wrapper">
|
||||||
<mat-checkbox labelPosition="before" required formControlName="allowMultipleDebitEntries" class="entries">
|
<mat-checkbox labelPosition="before" formControlName="allowMultipleDebitEntries" class="entries">
|
||||||
Multiple Debit Entries Allowed
|
Multiple Debit Entries Allowed
|
||||||
</mat-checkbox>
|
</mat-checkbox>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div fxFlex="48%" fxLayout="row" fxLayout.lt-md="column" class="rule-wrapper">
|
<div fxFlex="48%" fxLayout="row" fxLayout.lt-md="column" class="rule-wrapper">
|
||||||
<label fxFlex="50%">Affected GL Entry (Credit) Rule Type *</label>
|
<mat-label fxFlex="50%">Affected GL Entry (Credit) Rule Type *</mat-label>
|
||||||
<mat-radio-group fxFlex="50%" fxLayout="row" fxLayoutGap="5%" formControlName="creditRuleType">
|
<mat-radio-group fxFlex="50%" fxLayout="row" fxLayoutGap="5%" formControlName="creditRuleType">
|
||||||
<mat-radio-button value="fixedAccount">Fixed Account</mat-radio-button>
|
<mat-radio-button value="fixedAccount">Fixed Account</mat-radio-button>
|
||||||
<mat-radio-button value="listOfAccounts">List of Accounts</mat-radio-button>
|
<mat-radio-button value="listOfAccounts">List of Accounts</mat-radio-button>
|
||||||
@@ -61,7 +71,8 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<mat-form-field fxFlex="48%" *ngIf="accountingRuleForm.controls.creditRuleType.value === 'fixedAccount'">
|
<mat-form-field fxFlex="48%" *ngIf="accountingRuleForm.controls.creditRuleType.value === 'fixedAccount'">
|
||||||
<mat-select placeholder="Account to Credit" required formControlName="accountToCredit">
|
<mat-label>Account to Credit</mat-label>
|
||||||
|
<mat-select formControlName="accountToCredit">
|
||||||
<mat-option *ngFor="let glAccount of glAccountData" [value]="glAccount.id">
|
<mat-option *ngFor="let glAccount of glAccountData" [value]="glAccount.id">
|
||||||
{{ glAccount.name }}
|
{{ glAccount.name }}
|
||||||
</mat-option>
|
</mat-option>
|
||||||
@@ -70,22 +81,24 @@
|
|||||||
|
|
||||||
<div fxFlex="48%" fxLayout="row" fxLayoutGap="2%" fxLayout.lt-md="column" *ngIf="accountingRuleForm.controls.creditRuleType.value === 'listOfAccounts'">
|
<div fxFlex="48%" fxLayout="row" fxLayoutGap="2%" fxLayout.lt-md="column" *ngIf="accountingRuleForm.controls.creditRuleType.value === 'listOfAccounts'">
|
||||||
<mat-form-field fxFlex="50%">
|
<mat-form-field fxFlex="50%">
|
||||||
<mat-select placeholder="Credit Tags" required formControlName="creditTags" multiple>
|
<mat-label>Credit Tags</mat-label>
|
||||||
|
<mat-select formControlName="creditTags" multiple>
|
||||||
<mat-option *ngFor="let creditTag of creditTagData" [value]="creditTag.id">
|
<mat-option *ngFor="let creditTag of creditTagData" [value]="creditTag.id">
|
||||||
{{ creditTag.name }}
|
{{ creditTag.name }}
|
||||||
</mat-option>
|
</mat-option>
|
||||||
</mat-select>
|
</mat-select>
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
|
|
||||||
<div fxFlex="50%" class="entries-wrapper">
|
<div fxFlex="50%" ngClass.gt-md="entries-wrapper">
|
||||||
<mat-checkbox labelPosition="before" required formControlName="allowMultipleCreditEntries" class="entries">
|
<mat-checkbox labelPosition="before" formControlName="allowMultipleCreditEntries" class="entries">
|
||||||
Multiple Credit Entries Allowed
|
Multiple Credit Entries Allowed
|
||||||
</mat-checkbox>
|
</mat-checkbox>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<mat-form-field fxFlex="98%">
|
<mat-form-field fxFlex="98%">
|
||||||
<textarea matInput placeholder="Description" formControlName="description"></textarea>
|
<mat-label>Description</mat-label>
|
||||||
|
<textarea matInput formControlName="description"></textarea>
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
@@ -93,8 +106,8 @@
|
|||||||
</mat-card-content>
|
</mat-card-content>
|
||||||
|
|
||||||
<mat-card-actions fxLayout="row" fxLayout.xs="column" fxLayoutAlign="center" fxLayoutGap="5px">
|
<mat-card-actions fxLayout="row" fxLayout.xs="column" fxLayoutAlign="center" fxLayoutGap="5px">
|
||||||
<button type="button" mat-raised-button [routerLink]="['/accounting/accounting-rules']">Cancel</button>
|
<button type="button" mat-raised-button [routerLink]="['../']">Cancel</button>
|
||||||
<button mat-raised-button color="primary">Submit</button>
|
<button mat-raised-button color="primary" [disabled]="!accountingRuleForm.valid">Submit</button>
|
||||||
</mat-card-actions>
|
</mat-card-actions>
|
||||||
|
|
||||||
</form>
|
</form>
|
||||||
|
|||||||
@@ -2,11 +2,6 @@
|
|||||||
margin: 17.5px 0 0 0;
|
margin: 17.5px 0 0 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.additional-selection {
|
|
||||||
opacity: 0.75;
|
|
||||||
font-size: 0.75em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.entries-wrapper {
|
.entries-wrapper {
|
||||||
position: relative;
|
position: relative;
|
||||||
|
|
||||||
|
|||||||
@@ -1,17 +1,17 @@
|
|||||||
|
/** Angular Imports */
|
||||||
import { Component, OnInit } from '@angular/core';
|
import { Component, OnInit } from '@angular/core';
|
||||||
import { FormGroup, FormBuilder, Validators, ValidatorFn, ValidationErrors } from '@angular/forms';
|
import { FormGroup, FormBuilder, Validators } from '@angular/forms';
|
||||||
import { Router } from '@angular/router';
|
import { Router, ActivatedRoute } from '@angular/router';
|
||||||
|
|
||||||
|
/** Custom Services */
|
||||||
import { AccountingService } from '../../accounting.service';
|
import { AccountingService } from '../../accounting.service';
|
||||||
|
|
||||||
const oneOfTheFieldsIsRequiredValidator: ValidatorFn = (accountingRuleForm: FormGroup): ValidationErrors | null => {
|
/** Custom Validators */
|
||||||
const accountToDebit = accountingRuleForm.controls.accountToDebit.value;
|
import { oneOfTheFieldsIsRequiredValidator } from '../one-of-the-fields-is-required.validator';
|
||||||
const debitTags = accountingRuleForm.controls.debitTags.value;
|
|
||||||
const accountToCredit = accountingRuleForm.controls.accountToCredit.value;
|
|
||||||
const creditTags = accountingRuleForm.controls.creditTags.value;
|
|
||||||
return ((accountToDebit || debitTags) && (accountToCredit || creditTags)) ? null : { 'error': true };
|
|
||||||
};
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create accounting rule component.
|
||||||
|
*/
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'mifosx-create-rule',
|
selector: 'mifosx-create-rule',
|
||||||
templateUrl: './create-rule.component.html',
|
templateUrl: './create-rule.component.html',
|
||||||
@@ -19,23 +19,48 @@ const oneOfTheFieldsIsRequiredValidator: ValidatorFn = (accountingRuleForm: Form
|
|||||||
})
|
})
|
||||||
export class CreateRuleComponent implements OnInit {
|
export class CreateRuleComponent implements OnInit {
|
||||||
|
|
||||||
|
/** Accounting rule form. */
|
||||||
accountingRuleForm: FormGroup;
|
accountingRuleForm: FormGroup;
|
||||||
|
/** Office data. */
|
||||||
officeData: any;
|
officeData: any;
|
||||||
|
/** GL Account data. */
|
||||||
glAccountData: any;
|
glAccountData: any;
|
||||||
|
/** Debit tag data. */
|
||||||
debitTagData: any;
|
debitTagData: any;
|
||||||
|
/** Credit tag data. */
|
||||||
creditTagData: any;
|
creditTagData: any;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the offices, gl accounts, debit tags and credit tags data from `resolve`.
|
||||||
|
* @param {FormBuilder} formBuilder Form Builder.
|
||||||
|
* @param {AccountingService} accountingService Accounting Service.
|
||||||
|
* @param {ActivatedRoute} route Activated Route.
|
||||||
|
* @param {Router} router Router for navigation.
|
||||||
|
*/
|
||||||
constructor(private formBuilder: FormBuilder,
|
constructor(private formBuilder: FormBuilder,
|
||||||
private accountingService: AccountingService,
|
private accountingService: AccountingService,
|
||||||
private router: Router) { }
|
private route: ActivatedRoute,
|
||||||
|
private router: Router) {
|
||||||
|
this.route.data.subscribe((data: { accountingRulesTemplate: any }) => {
|
||||||
|
this.officeData = data.accountingRulesTemplate.allowedOffices;
|
||||||
|
this.glAccountData = data.accountingRulesTemplate.allowedAccounts;
|
||||||
|
this.debitTagData = data.accountingRulesTemplate.allowedDebitTagOptions;
|
||||||
|
this.creditTagData = data.accountingRulesTemplate.allowedCreditTagOptions;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates and sets accounting rules form.
|
||||||
|
*/
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
this.createAccountingRulesForm();
|
this.createAccountingRuleForm();
|
||||||
this.getAccountingRulesTemplate();
|
|
||||||
this.setAccountingRulesForm();
|
this.setAccountingRulesForm();
|
||||||
}
|
}
|
||||||
|
|
||||||
createAccountingRulesForm() {
|
/**
|
||||||
|
* Creates accounting rule form.
|
||||||
|
*/
|
||||||
|
createAccountingRuleForm() {
|
||||||
this.accountingRuleForm = this.formBuilder.group({
|
this.accountingRuleForm = this.formBuilder.group({
|
||||||
'name': ['', Validators.required],
|
'name': ['', Validators.required],
|
||||||
'officeId': ['', Validators.required],
|
'officeId': ['', Validators.required],
|
||||||
@@ -51,40 +76,52 @@ export class CreateRuleComponent implements OnInit {
|
|||||||
}, { validator: oneOfTheFieldsIsRequiredValidator });
|
}, { validator: oneOfTheFieldsIsRequiredValidator });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets accounting rule form for selected accounting rule type.
|
||||||
|
*/
|
||||||
setAccountingRulesForm() {
|
setAccountingRulesForm() {
|
||||||
this.accountingRuleForm.get('debitRuleType').valueChanges.subscribe(debitRuleType => {
|
this.accountingRuleForm.get('debitRuleType').valueChanges.subscribe((debitRuleType: string) => {
|
||||||
if (debitRuleType === 'fixedAccount') {
|
if (debitRuleType === 'fixedAccount') {
|
||||||
this.accountingRuleForm.get('debitTags').reset();
|
this.accountingRuleForm.get('debitTags').reset();
|
||||||
this.accountingRuleForm.get('allowMultipleDebitEntries').reset();
|
this.accountingRuleForm.get('allowMultipleDebitEntries').reset();
|
||||||
} else {
|
} else {
|
||||||
|
this.accountingRuleForm.get('accountToDebit').reset();
|
||||||
this.accountingRuleForm.get('allowMultipleDebitEntries').setValue(false);
|
this.accountingRuleForm.get('allowMultipleDebitEntries').setValue(false);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
this.accountingRuleForm.get('creditRuleType').valueChanges.subscribe(creditRuleType => {
|
this.accountingRuleForm.get('creditRuleType').valueChanges.subscribe((creditRuleType: string) => {
|
||||||
if (creditRuleType === 'fixedAccount') {
|
if (creditRuleType === 'fixedAccount') {
|
||||||
this.accountingRuleForm.get('creditTags').reset();
|
this.accountingRuleForm.get('creditTags').reset();
|
||||||
this.accountingRuleForm.get('allowMultipleCreditEntries').reset();
|
this.accountingRuleForm.get('allowMultipleCreditEntries').reset();
|
||||||
} else {
|
} else {
|
||||||
|
this.accountingRuleForm.get('accountToCredit').reset();
|
||||||
this.accountingRuleForm.get('allowMultipleCreditEntries').setValue(false);
|
this.accountingRuleForm.get('allowMultipleCreditEntries').setValue(false);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
getAccountingRulesTemplate() {
|
/**
|
||||||
this.accountingService.getAccountingRulesTemplate().subscribe((accountingRulesData: any) => {
|
* Submits the accounting rule form and creates accounting rule,
|
||||||
this.officeData = accountingRulesData.allowedOffices;
|
* if successful redirects to view created rule.
|
||||||
this.glAccountData = accountingRulesData.allowedAccounts;
|
*/
|
||||||
this.debitTagData = accountingRulesData.allowedDebitTagOptions;
|
|
||||||
this.creditTagData = accountingRulesData.allowedCreditTagOptions;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
submit() {
|
submit() {
|
||||||
const accountingRule = this.accountingRuleForm.value;
|
const accountingRule = this.accountingRuleForm.value;
|
||||||
|
if (accountingRule.debitRuleType === 'fixedAccount') {
|
||||||
|
delete accountingRule.debitTags;
|
||||||
|
delete accountingRule.allowMultipleDebitEntries;
|
||||||
|
} else {
|
||||||
|
delete accountingRule.accountToDebit;
|
||||||
|
}
|
||||||
|
if (accountingRule.creditRuleType === 'fixedAccount') {
|
||||||
|
delete accountingRule.creditTags;
|
||||||
|
delete accountingRule.allowMultipleCreditEntries;
|
||||||
|
} else {
|
||||||
|
delete accountingRule.accountToCredit;
|
||||||
|
}
|
||||||
delete accountingRule.debitRuleType;
|
delete accountingRule.debitRuleType;
|
||||||
delete accountingRule.creditRuleType;
|
delete accountingRule.creditRuleType;
|
||||||
this.accountingService.createAccountingRule(accountingRule).subscribe((response: any) => {
|
this.accountingService.createAccountingRule(accountingRule).subscribe((response: any) => {
|
||||||
this.router.navigate(['/accounting/accounting-rules/view', response.resourceId]);
|
this.router.navigate(['../view', response.resourceId], { relativeTo: this.route });
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -9,19 +9,27 @@
|
|||||||
<div fxLayout="row wrap" fxLayoutGap="2%" fxLayout.lt-md="column">
|
<div fxLayout="row wrap" fxLayoutGap="2%" fxLayout.lt-md="column">
|
||||||
|
|
||||||
<mat-form-field fxFlex="48%">
|
<mat-form-field fxFlex="48%">
|
||||||
<input matInput placeholder="Accounting Rule Name" required formControlName="name">
|
<mat-label>Accounting Rule Name</mat-label>
|
||||||
|
<input matInput required formControlName="name">
|
||||||
|
<mat-error *ngIf="accountingRuleForm.controls.name.hasError('required')">
|
||||||
|
Accounting Rule Name is <strong>required</strong>
|
||||||
|
</mat-error>
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
|
|
||||||
<mat-form-field fxFlex="48%">
|
<mat-form-field fxFlex="48%">
|
||||||
<mat-select placeholder="Office" required formControlName="officeId">
|
<mat-label>Office</mat-label>
|
||||||
|
<mat-select required formControlName="officeId">
|
||||||
<mat-option *ngFor="let office of officeData" [value]="office.id">
|
<mat-option *ngFor="let office of officeData" [value]="office.id">
|
||||||
{{ office.name }}
|
{{ office.name }}
|
||||||
</mat-option>
|
</mat-option>
|
||||||
</mat-select>
|
</mat-select>
|
||||||
|
<mat-error *ngIf="accountingRuleForm.controls.officeId.hasError('required')">
|
||||||
|
Office is <strong>required</strong>
|
||||||
|
</mat-error>
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
|
|
||||||
<div fxFlex="48%" fxLayout="row" fxLayout.lt-md="column" class="rule-wrapper">
|
<div fxFlex="48%" fxLayout="row" fxLayout.lt-md="column" class="rule-wrapper">
|
||||||
<label fxFlex="50%">Affected GL Entry (Debit) Rule Type *</label>
|
<mat-label fxFlex="50%">Affected GL Entry (Debit) Rule Type *</mat-label>
|
||||||
<mat-radio-group fxFlex="50%" fxLayout="row" fxLayoutGap="5%" formControlName="debitRuleType">
|
<mat-radio-group fxFlex="50%" fxLayout="row" fxLayoutGap="5%" formControlName="debitRuleType">
|
||||||
<mat-radio-button value="fixedAccount">Fixed Account</mat-radio-button>
|
<mat-radio-button value="fixedAccount">Fixed Account</mat-radio-button>
|
||||||
<mat-radio-button value="listOfAccounts">List of Accounts</mat-radio-button>
|
<mat-radio-button value="listOfAccounts">List of Accounts</mat-radio-button>
|
||||||
@@ -29,7 +37,8 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<mat-form-field fxFlex="48%" *ngIf="accountingRuleForm.controls.debitRuleType.value === 'fixedAccount'">
|
<mat-form-field fxFlex="48%" *ngIf="accountingRuleForm.controls.debitRuleType.value === 'fixedAccount'">
|
||||||
<mat-select placeholder="Account to Debit" required formControlName="accountToDebit">
|
<mat-label>Account to Debit</mat-label>
|
||||||
|
<mat-select formControlName="accountToDebit">
|
||||||
<mat-option *ngFor="let glAccount of glAccountData" [value]="glAccount.id">
|
<mat-option *ngFor="let glAccount of glAccountData" [value]="glAccount.id">
|
||||||
{{ glAccount.name }}
|
{{ glAccount.name }}
|
||||||
</mat-option>
|
</mat-option>
|
||||||
@@ -38,22 +47,23 @@
|
|||||||
|
|
||||||
<div fxFlex="48%" fxLayout="row" fxLayoutGap="2%" fxLayout.lt-md="column" *ngIf="accountingRuleForm.controls.debitRuleType.value === 'listOfAccounts'">
|
<div fxFlex="48%" fxLayout="row" fxLayoutGap="2%" fxLayout.lt-md="column" *ngIf="accountingRuleForm.controls.debitRuleType.value === 'listOfAccounts'">
|
||||||
<mat-form-field fxFlex="50%">
|
<mat-form-field fxFlex="50%">
|
||||||
<mat-select placeholder="Debit Tags" required formControlName="debitTags" multiple>
|
<mat-label>Debit Tags</mat-label>
|
||||||
|
<mat-select formControlName="debitTags" multiple>
|
||||||
<mat-option *ngFor="let debitTag of debitTagData" [value]="debitTag.id">
|
<mat-option *ngFor="let debitTag of debitTagData" [value]="debitTag.id">
|
||||||
{{ debitTag.name }}
|
{{ debitTag.name }}
|
||||||
</mat-option>
|
</mat-option>
|
||||||
</mat-select>
|
</mat-select>
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
|
|
||||||
<div fxFlex="50%" class="entries-wrapper">
|
<div fxFlex="50%" ngClass.gt-md="entries-wrapper">
|
||||||
<mat-checkbox labelPosition="before" required formControlName="allowMultipleDebitEntries" class="entries">
|
<mat-checkbox labelPosition="before" formControlName="allowMultipleDebitEntries" class="entries">
|
||||||
Multiple Debit Entries Allowed
|
Multiple Debit Entries Allowed
|
||||||
</mat-checkbox>
|
</mat-checkbox>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div fxFlex="48%" fxLayout="row" fxLayout.lt-md="column" class="rule-wrapper">
|
<div fxFlex="48%" fxLayout="row" fxLayout.lt-md="column" class="rule-wrapper">
|
||||||
<label fxFlex="50%">Affected GL Entry (Credit) Rule Type *</label>
|
<mat-label fxFlex="50%">Affected GL Entry (Credit) Rule Type *</mat-label>
|
||||||
<mat-radio-group fxFlex="50%" fxLayout="row" fxLayoutGap="5%" formControlName="creditRuleType">
|
<mat-radio-group fxFlex="50%" fxLayout="row" fxLayoutGap="5%" formControlName="creditRuleType">
|
||||||
<mat-radio-button value="fixedAccount">Fixed Account</mat-radio-button>
|
<mat-radio-button value="fixedAccount">Fixed Account</mat-radio-button>
|
||||||
<mat-radio-button value="listOfAccounts">List of Accounts</mat-radio-button>
|
<mat-radio-button value="listOfAccounts">List of Accounts</mat-radio-button>
|
||||||
@@ -61,7 +71,8 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<mat-form-field fxFlex="48%" *ngIf="accountingRuleForm.controls.creditRuleType.value === 'fixedAccount'">
|
<mat-form-field fxFlex="48%" *ngIf="accountingRuleForm.controls.creditRuleType.value === 'fixedAccount'">
|
||||||
<mat-select placeholder="Account to Credit" required formControlName="accountToCredit">
|
<mat-label>Account to Credit</mat-label>
|
||||||
|
<mat-select formControlName="accountToCredit">
|
||||||
<mat-option *ngFor="let glAccount of glAccountData" [value]="glAccount.id">
|
<mat-option *ngFor="let glAccount of glAccountData" [value]="glAccount.id">
|
||||||
{{ glAccount.name }}
|
{{ glAccount.name }}
|
||||||
</mat-option>
|
</mat-option>
|
||||||
@@ -70,22 +81,24 @@
|
|||||||
|
|
||||||
<div fxFlex="48%" fxLayout="row" fxLayoutGap="2%" fxLayout.lt-md="column" *ngIf="accountingRuleForm.controls.creditRuleType.value === 'listOfAccounts'">
|
<div fxFlex="48%" fxLayout="row" fxLayoutGap="2%" fxLayout.lt-md="column" *ngIf="accountingRuleForm.controls.creditRuleType.value === 'listOfAccounts'">
|
||||||
<mat-form-field fxFlex="50%">
|
<mat-form-field fxFlex="50%">
|
||||||
<mat-select placeholder="Credit Tags" required formControlName="creditTags" multiple>
|
<mat-label>Credit Tags</mat-label>
|
||||||
|
<mat-select formControlName="creditTags" multiple>
|
||||||
<mat-option *ngFor="let creditTag of creditTagData" [value]="creditTag.id">
|
<mat-option *ngFor="let creditTag of creditTagData" [value]="creditTag.id">
|
||||||
{{ creditTag.name }}
|
{{ creditTag.name }}
|
||||||
</mat-option>
|
</mat-option>
|
||||||
</mat-select>
|
</mat-select>
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
|
|
||||||
<div fxFlex="50%" class="entries-wrapper">
|
<div fxFlex="50%" ngClass.gt-md="entries-wrapper">
|
||||||
<mat-checkbox labelPosition="before" required formControlName="allowMultipleCreditEntries" class="entries">
|
<mat-checkbox labelPosition="before" formControlName="allowMultipleCreditEntries" class="entries">
|
||||||
Multiple Credit Entries Allowed
|
Multiple Credit Entries Allowed
|
||||||
</mat-checkbox>
|
</mat-checkbox>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<mat-form-field fxFlex="98%">
|
<mat-form-field fxFlex="98%">
|
||||||
<textarea matInput placeholder="Description" formControlName="description"></textarea>
|
<mat-label>Description</mat-label>
|
||||||
|
<textarea matInput formControlName="description"></textarea>
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
@@ -93,8 +106,8 @@
|
|||||||
</mat-card-content>
|
</mat-card-content>
|
||||||
|
|
||||||
<mat-card-actions fxLayout="row" fxLayout.xs="column" fxLayoutAlign="center" fxLayoutGap="5px">
|
<mat-card-actions fxLayout="row" fxLayout.xs="column" fxLayoutAlign="center" fxLayoutGap="5px">
|
||||||
<button type="button" mat-raised-button [routerLink]="['/accounting/accounting-rules/view', accountingRule?.id]">Cancel</button>
|
<button type="button" mat-raised-button [routerLink]="['../']">Cancel</button>
|
||||||
<button mat-raised-button color="primary">Submit</button>
|
<button mat-raised-button color="primary" [disabled]="accountingRuleForm.pristine || !accountingRuleForm.valid">Submit</button>
|
||||||
</mat-card-actions>
|
</mat-card-actions>
|
||||||
|
|
||||||
</form>
|
</form>
|
||||||
|
|||||||
@@ -2,11 +2,6 @@
|
|||||||
margin: 17.5px 0 0 0;
|
margin: 17.5px 0 0 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.additional-selection {
|
|
||||||
opacity: 0.75;
|
|
||||||
font-size: 0.75em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.entries-wrapper {
|
.entries-wrapper {
|
||||||
position: relative;
|
position: relative;
|
||||||
|
|
||||||
|
|||||||
@@ -1,17 +1,17 @@
|
|||||||
|
/** Angular Imports */
|
||||||
import { Component, OnInit } from '@angular/core';
|
import { Component, OnInit } from '@angular/core';
|
||||||
import { FormGroup, FormBuilder, Validators, ValidatorFn, ValidationErrors } from '@angular/forms';
|
import { FormGroup, FormBuilder, Validators } from '@angular/forms';
|
||||||
import { Router, ActivatedRoute } from '@angular/router';
|
import { Router, ActivatedRoute } from '@angular/router';
|
||||||
|
|
||||||
|
/** Custom Services */
|
||||||
import { AccountingService } from '../../accounting.service';
|
import { AccountingService } from '../../accounting.service';
|
||||||
|
|
||||||
const oneOfTheFieldsIsRequiredValidator: ValidatorFn = (accountingRuleForm: FormGroup): ValidationErrors | null => {
|
/** Custom Validators */
|
||||||
const accountToDebit = accountingRuleForm.controls.accountToDebit.value;
|
import { oneOfTheFieldsIsRequiredValidator } from '../one-of-the-fields-is-required.validator';
|
||||||
const debitTags = accountingRuleForm.controls.debitTags.value;
|
|
||||||
const accountToCredit = accountingRuleForm.controls.accountToCredit.value;
|
|
||||||
const creditTags = accountingRuleForm.controls.creditTags.value;
|
|
||||||
return ((accountToDebit || debitTags) && (accountToCredit || creditTags)) ? null : { 'error': true };
|
|
||||||
};
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Edit accounting rule component.
|
||||||
|
*/
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'mifosx-edit-rule',
|
selector: 'mifosx-edit-rule',
|
||||||
templateUrl: './edit-rule.component.html',
|
templateUrl: './edit-rule.component.html',
|
||||||
@@ -19,29 +19,54 @@ const oneOfTheFieldsIsRequiredValidator: ValidatorFn = (accountingRuleForm: Form
|
|||||||
})
|
})
|
||||||
export class EditRuleComponent implements OnInit {
|
export class EditRuleComponent implements OnInit {
|
||||||
|
|
||||||
|
/** Accounting rule form. */
|
||||||
accountingRuleForm: FormGroup;
|
accountingRuleForm: FormGroup;
|
||||||
|
/** Accounting rule. */
|
||||||
accountingRule: any;
|
accountingRule: any;
|
||||||
|
/** Office data. */
|
||||||
officeData: any;
|
officeData: any;
|
||||||
|
/** GL Account data. */
|
||||||
glAccountData: any;
|
glAccountData: any;
|
||||||
|
/** Debit tag data. */
|
||||||
debitTagData: any;
|
debitTagData: any;
|
||||||
|
/** Credit tag data. */
|
||||||
creditTagData: any;
|
creditTagData: any;
|
||||||
|
|
||||||
constructor(private route: ActivatedRoute,
|
/**
|
||||||
private formBuilder: FormBuilder,
|
* Retrieves the offices, gl accounts, debit tags, credit tags and accounting rule data from `resolve`.
|
||||||
|
* @param {FormBuilder} formBuilder Form Builder.
|
||||||
|
* @param {AccountingService} accountingService Accounting Service.
|
||||||
|
* @param {ActivatedRoute} route Activated Route.
|
||||||
|
* @param {Router} router Router for navigation.
|
||||||
|
*/
|
||||||
|
constructor(private formBuilder: FormBuilder,
|
||||||
private accountingService: AccountingService,
|
private accountingService: AccountingService,
|
||||||
|
private route: ActivatedRoute,
|
||||||
private router: Router) {
|
private router: Router) {
|
||||||
this.route.data.subscribe((data: { accountingRule: any }) => {
|
this.route.data.subscribe((data: {
|
||||||
this.accountingRule = data.accountingRule;
|
accountingRulesTemplate: any,
|
||||||
});
|
accountingRule: any
|
||||||
|
}) => {
|
||||||
|
this.officeData = data.accountingRulesTemplate.allowedOffices;
|
||||||
|
this.glAccountData = data.accountingRulesTemplate.allowedAccounts;
|
||||||
|
this.debitTagData = data.accountingRulesTemplate.allowedDebitTagOptions;
|
||||||
|
this.creditTagData = data.accountingRulesTemplate.allowedCreditTagOptions;
|
||||||
|
this.accountingRule = data.accountingRule;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates and sets accounting rule form.
|
||||||
|
*/
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
this.createAccountingRulesForm();
|
this.createAccountingRuleForm();
|
||||||
this.getAccountingRulesTemplate();
|
|
||||||
this.setAccountingRulesForm();
|
this.setAccountingRulesForm();
|
||||||
}
|
}
|
||||||
|
|
||||||
createAccountingRulesForm() {
|
/**
|
||||||
|
* Creates accounting rule form.
|
||||||
|
*/
|
||||||
|
createAccountingRuleForm() {
|
||||||
this.accountingRuleForm = this.formBuilder.group({
|
this.accountingRuleForm = this.formBuilder.group({
|
||||||
'name': [this.accountingRule.name, Validators.required],
|
'name': [this.accountingRule.name, Validators.required],
|
||||||
'officeId': [this.accountingRule.officeId, Validators.required],
|
'officeId': [this.accountingRule.officeId, Validators.required],
|
||||||
@@ -57,12 +82,16 @@ export class EditRuleComponent implements OnInit {
|
|||||||
}, { validator: oneOfTheFieldsIsRequiredValidator });
|
}, { validator: oneOfTheFieldsIsRequiredValidator });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets accounting rule form for selected accounting rule type.
|
||||||
|
*/
|
||||||
setAccountingRulesForm() {
|
setAccountingRulesForm() {
|
||||||
this.accountingRuleForm.get('debitRuleType').valueChanges.subscribe(debitRuleType => {
|
this.accountingRuleForm.get('debitRuleType').valueChanges.subscribe(debitRuleType => {
|
||||||
if (debitRuleType === 'fixedAccount') {
|
if (debitRuleType === 'fixedAccount') {
|
||||||
this.accountingRuleForm.get('debitTags').reset();
|
this.accountingRuleForm.get('debitTags').reset();
|
||||||
this.accountingRuleForm.get('allowMultipleDebitEntries').reset();
|
this.accountingRuleForm.get('allowMultipleDebitEntries').reset();
|
||||||
} else {
|
} else {
|
||||||
|
this.accountingRuleForm.get('accountToDebit').reset();
|
||||||
this.accountingRuleForm.get('allowMultipleDebitEntries').setValue(false);
|
this.accountingRuleForm.get('allowMultipleDebitEntries').setValue(false);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -71,6 +100,7 @@ export class EditRuleComponent implements OnInit {
|
|||||||
this.accountingRuleForm.get('creditTags').reset();
|
this.accountingRuleForm.get('creditTags').reset();
|
||||||
this.accountingRuleForm.get('allowMultipleCreditEntries').reset();
|
this.accountingRuleForm.get('allowMultipleCreditEntries').reset();
|
||||||
} else {
|
} else {
|
||||||
|
this.accountingRuleForm.get('accountToCredit').reset();
|
||||||
this.accountingRuleForm.get('allowMultipleCreditEntries').setValue(false);
|
this.accountingRuleForm.get('allowMultipleCreditEntries').setValue(false);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -94,21 +124,28 @@ export class EditRuleComponent implements OnInit {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
getAccountingRulesTemplate() {
|
/**
|
||||||
this.accountingService.getAccountingRulesTemplate().subscribe((accountingRulesData: any) => {
|
* Submits the accounting rule form and updates accounting rule,
|
||||||
this.officeData = accountingRulesData.allowedOffices;
|
* if successful redirects to view updated rule.
|
||||||
this.glAccountData = accountingRulesData.allowedAccounts;
|
*/
|
||||||
this.debitTagData = accountingRulesData.allowedDebitTagOptions;
|
|
||||||
this.creditTagData = accountingRulesData.allowedCreditTagOptions;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
submit() {
|
submit() {
|
||||||
const accountingRule = this.accountingRuleForm.value;
|
const accountingRule = this.accountingRuleForm.value;
|
||||||
|
if (accountingRule.debitRuleType === 'fixedAccount') {
|
||||||
|
delete accountingRule.debitTags;
|
||||||
|
delete accountingRule.allowMultipleDebitEntries;
|
||||||
|
} else {
|
||||||
|
delete accountingRule.accountToDebit;
|
||||||
|
}
|
||||||
|
if (accountingRule.creditRuleType === 'fixedAccount') {
|
||||||
|
delete accountingRule.creditTags;
|
||||||
|
delete accountingRule.allowMultipleCreditEntries;
|
||||||
|
} else {
|
||||||
|
delete accountingRule.accountToCredit;
|
||||||
|
}
|
||||||
delete accountingRule.debitRuleType;
|
delete accountingRule.debitRuleType;
|
||||||
delete accountingRule.creditRuleType;
|
delete accountingRule.creditRuleType;
|
||||||
this.accountingService.updateAccountingRule(this.accountingRule.id, accountingRule).subscribe((response: any) => {
|
this.accountingService.updateAccountingRule(this.accountingRule.id, accountingRule).subscribe((response: any) => {
|
||||||
this.router.navigate(['/accounting/accounting-rules/view', response.resourceId]);
|
this.router.navigate(['../../', response.resourceId], { relativeTo: this.route });
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,11 @@
|
|||||||
|
/** Angular Imports */
|
||||||
|
import { FormGroup, ValidatorFn, ValidationErrors } from '@angular/forms';
|
||||||
|
|
||||||
|
/** Validates that one of the fields for debit or credit is filled for a given accounting rule type. */
|
||||||
|
export const oneOfTheFieldsIsRequiredValidator: ValidatorFn = (accountingRuleForm: FormGroup): ValidationErrors | null => {
|
||||||
|
const accountToDebit = accountingRuleForm.controls.accountToDebit.value;
|
||||||
|
const debitTags = accountingRuleForm.controls.debitTags.value;
|
||||||
|
const accountToCredit = accountingRuleForm.controls.accountToCredit.value;
|
||||||
|
const creditTags = accountingRuleForm.controls.creditTags.value;
|
||||||
|
return ((accountToDebit || debitTags) && (accountToCredit || creditTags)) ? null : { 'error': true };
|
||||||
|
};
|
||||||
@@ -1,9 +1,11 @@
|
|||||||
<div fxLayout="row" fxLayoutAlign="end" fxLayoutGap="2%" fxLayout.lt-md="column" class="container m-b-20">
|
<div fxLayout="row" fxLayoutAlign="end" fxLayoutGap="2%" fxLayout.lt-md="column" class="container m-b-20">
|
||||||
<button mat-raised-button color="primary" [routerLink]="['/accounting/accounting-rules/view', accountingRule?.id, 'edit']">
|
<button mat-raised-button color="primary" [routerLink]="['edit']">
|
||||||
<mat-icon>edit</mat-icon> Edit
|
<fa-icon icon="edit"></fa-icon>
|
||||||
|
Edit
|
||||||
</button>
|
</button>
|
||||||
<button mat-raised-button color="warn" (click)="deleteAccountingRule()">
|
<button mat-raised-button color="warn" (click)="deleteAccountingRule()">
|
||||||
<mat-icon>delete</mat-icon> Delete
|
<fa-icon icon="trash"></fa-icon>
|
||||||
|
Delete
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -25,11 +27,11 @@
|
|||||||
{{ accountingRule.officeName }}
|
{{ accountingRule.officeName }}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div fxFlex="50%" class="header">
|
<div fxFlex="50%" class="header" *ngIf="accountingRule.description">
|
||||||
Description
|
Description
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div fxFlex="50%">
|
<div fxFlex="50%" *ngIf="accountingRule.description">
|
||||||
{{ accountingRule.description }}
|
{{ accountingRule.description }}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -2,9 +2,9 @@
|
|||||||
div {
|
div {
|
||||||
margin: 1rem 0;
|
margin: 1rem 0;
|
||||||
word-wrap: break-word;
|
word-wrap: break-word;
|
||||||
}
|
|
||||||
|
|
||||||
.header {
|
&.header {
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,17 @@
|
|||||||
|
/** Angular Imports */
|
||||||
import { Component, OnInit } from '@angular/core';
|
import { Component, OnInit } from '@angular/core';
|
||||||
import { ActivatedRoute, Router } from '@angular/router';
|
import { ActivatedRoute, Router } from '@angular/router';
|
||||||
import { MatDialog } from '@angular/material';
|
import { MatDialog } from '@angular/material';
|
||||||
|
|
||||||
|
/** Custom Services */
|
||||||
import { AccountingService } from '../../accounting.service';
|
import { AccountingService } from '../../accounting.service';
|
||||||
|
|
||||||
|
/** Custom Components */
|
||||||
import { DeleteDialogComponent } from '../../../shared/delete-dialog/delete-dialog.component';
|
import { DeleteDialogComponent } from '../../../shared/delete-dialog/delete-dialog.component';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* View accounting rule component.
|
||||||
|
*/
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'mifosx-view-rule',
|
selector: 'mifosx-view-rule',
|
||||||
templateUrl: './view-rule.component.html',
|
templateUrl: './view-rule.component.html',
|
||||||
@@ -12,11 +19,19 @@ import { DeleteDialogComponent } from '../../../shared/delete-dialog/delete-dial
|
|||||||
})
|
})
|
||||||
export class ViewRuleComponent implements OnInit {
|
export class ViewRuleComponent implements OnInit {
|
||||||
|
|
||||||
|
/** Accounting rule. */
|
||||||
accountingRule: any;
|
accountingRule: any;
|
||||||
|
|
||||||
constructor(private route: ActivatedRoute,
|
/**
|
||||||
|
* Retrieves the accounting rule data from `resolve`.
|
||||||
|
* @param {AccountingService} accountingService Accounting Service.
|
||||||
|
* @param {ActivatedRoute} route Activated Route.
|
||||||
|
* @param {Router} router Router for navigation.
|
||||||
|
* @param {MatDialog} dialog Dialog reference.
|
||||||
|
*/
|
||||||
|
constructor(private accountingService: AccountingService,
|
||||||
|
private route: ActivatedRoute,
|
||||||
private router: Router,
|
private router: Router,
|
||||||
private accountingService: AccountingService,
|
|
||||||
public dialog: MatDialog) {
|
public dialog: MatDialog) {
|
||||||
this.route.data.subscribe((data: { accountingRule: any }) => {
|
this.route.data.subscribe((data: { accountingRule: any }) => {
|
||||||
this.accountingRule = data.accountingRule;
|
this.accountingRule = data.accountingRule;
|
||||||
@@ -26,6 +41,9 @@ export class ViewRuleComponent implements OnInit {
|
|||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deletes the accounting rule and redirects to accounting rules.
|
||||||
|
*/
|
||||||
deleteAccountingRule() {
|
deleteAccountingRule() {
|
||||||
const deleteAccountingRuleDialogRef = this.dialog.open(DeleteDialogComponent, {
|
const deleteAccountingRuleDialogRef = this.dialog.open(DeleteDialogComponent, {
|
||||||
data: { deleteContext: `accounting rule ${this.accountingRule.id}` }
|
data: { deleteContext: `accounting rule ${this.accountingRule.id}` }
|
||||||
|
|||||||
@@ -1,19 +0,0 @@
|
|||||||
import { Injectable } from '@angular/core';
|
|
||||||
import { Resolve, ActivatedRouteSnapshot } from '@angular/router';
|
|
||||||
|
|
||||||
import { Observable } from 'rxjs';
|
|
||||||
|
|
||||||
import { AccountingService } from '../../accounting.service';
|
|
||||||
|
|
||||||
@Injectable()
|
|
||||||
export class ViewAccountingRuleResolver implements Resolve<Object> {
|
|
||||||
|
|
||||||
constructor(private accountingService: AccountingService) {}
|
|
||||||
|
|
||||||
resolve(route: ActivatedRouteSnapshot): Observable<any> {
|
|
||||||
const id = route.paramMap.get('id');
|
|
||||||
|
|
||||||
return this.accountingService.getAccountingRule(id);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,84 +1,107 @@
|
|||||||
<mat-card class="container">
|
<div class="container">
|
||||||
|
|
||||||
<div fxLayout="row" fxLayout.lt-md="column">
|
<mat-card>
|
||||||
|
|
||||||
<div fxFlex="50%">
|
<div fxLayout="row" fxLayout.lt-md="column">
|
||||||
|
|
||||||
<mat-nav-list>
|
<div fxFlex="50%">
|
||||||
|
|
||||||
<mat-list-item [routerLink]="['/accounting/frequent-postings']">
|
<mat-nav-list>
|
||||||
<mat-icon matListIcon>repeat</mat-icon>
|
|
||||||
<h4 matLine>Frequent Postings</h4>
|
|
||||||
<p matLine>These are predefined postings</p>
|
|
||||||
</mat-list-item>
|
|
||||||
|
|
||||||
<mat-list-item [routerLink]="['/accounting/journal-entries/create']">
|
<mat-list-item [routerLink]="['journal-entries/frequent-postings']">
|
||||||
<mat-icon matListIcon>add</mat-icon>
|
<mat-icon matListIcon>
|
||||||
<h4 matLine>Create Journal Entries</h4>
|
<fa-icon icon="sync" size="sm"></fa-icon>
|
||||||
<p matLine>Manual journal entry transactions recorded in a journal</p>
|
</mat-icon>
|
||||||
</mat-list-item>
|
<h4 matLine>Frequent Postings</h4>
|
||||||
|
<p matLine>These are predefined postings</p>
|
||||||
|
</mat-list-item>
|
||||||
|
|
||||||
<mat-list-item [routerLink]="['/accounting/journal-entries']">
|
<mat-list-item [routerLink]="['journal-entries/create']">
|
||||||
<mat-icon matListIcon>search</mat-icon>
|
<mat-icon matListIcon>
|
||||||
<h4 matLine>Search Journal Entries</h4>
|
<fa-icon icon="plus" size="sm"></fa-icon>
|
||||||
<p matLine>Advanced search option for journal entries</p>
|
</mat-icon>
|
||||||
</mat-list-item>
|
<h4 matLine>Create Journal Entries</h4>
|
||||||
|
<p matLine>Manual journal entry transactions recorded in a journal</p>
|
||||||
|
</mat-list-item>
|
||||||
|
|
||||||
<mat-list-item [routerLink]="['/accounting/financial-activity-mappings']">
|
<mat-list-item [routerLink]="['journal-entries']">
|
||||||
<mat-icon matListIcon>link</mat-icon>
|
<mat-icon matListIcon>
|
||||||
<h4 matLine>Accounts Linked to Financial Activities</h4>
|
<fa-icon icon="search" size="sm"></fa-icon>
|
||||||
<p matLine>List of Financial Activities and GL Account Mappings</p>
|
</mat-icon>
|
||||||
</mat-list-item>
|
<h4 matLine>Search Journal Entries</h4>
|
||||||
|
<p matLine>Advanced search option for journal entries</p>
|
||||||
|
</mat-list-item>
|
||||||
|
|
||||||
<mat-list-item [routerLink]="['/accounting/migrate-opening-balances']">
|
<mat-list-item [routerLink]="['financial-activity-mappings']">
|
||||||
<mat-icon matListIcon>monetization_on</mat-icon>
|
<mat-icon matListIcon>
|
||||||
<h4 matLine>Migrate Opening Balances (Office-wise)</h4>
|
<fa-icon icon="link" size="sm"></fa-icon>
|
||||||
<p matLine>Set or update office-level opening balances for GL accounts</p>
|
</mat-icon>
|
||||||
</mat-list-item>
|
<h4 matLine>Accounts Linked to Financial Activities</h4>
|
||||||
|
<p matLine>List of Financial Activities and GL Account Mappings</p>
|
||||||
|
</mat-list-item>
|
||||||
|
|
||||||
</mat-nav-list>
|
<mat-list-item [routerLink]="['migrate-opening-balances']">
|
||||||
|
<mat-icon matListIcon>
|
||||||
|
<fa-icon icon="hand-holding-usd" size="sm"></fa-icon>
|
||||||
|
</mat-icon>
|
||||||
|
<h4 matLine>Migrate Opening Balances (Office-wise)</h4>
|
||||||
|
<p matLine>Set or update office-level opening balances for GL accounts</p>
|
||||||
|
</mat-list-item>
|
||||||
|
|
||||||
|
</mat-nav-list>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div fxFlex="50%">
|
||||||
|
|
||||||
|
<mat-nav-list>
|
||||||
|
|
||||||
|
<mat-list-item [routerLink]="['chart-of-accounts']">
|
||||||
|
<mat-icon matListIcon>
|
||||||
|
<fa-icon icon="sitemap" size="sm"></fa-icon>
|
||||||
|
</mat-icon>
|
||||||
|
<h4 matLine>Chart of Accounts</h4>
|
||||||
|
<p matLine>List of accounts used by the organisation</p>
|
||||||
|
</mat-list-item>
|
||||||
|
|
||||||
|
<mat-list-item [routerLink]="['closing-entries']">
|
||||||
|
<mat-icon matListIcon>
|
||||||
|
<fa-icon icon="archive" size="sm"></fa-icon>
|
||||||
|
</mat-icon>
|
||||||
|
<h4 matLine>Closing Entries</h4>
|
||||||
|
<p matLine>Journal entries made at the end of accounting period</p>
|
||||||
|
</mat-list-item>
|
||||||
|
|
||||||
|
<mat-list-item [routerLink]="['accounting-rules']">
|
||||||
|
<mat-icon matListIcon>
|
||||||
|
<fa-icon icon="list" size="sm"></fa-icon>
|
||||||
|
</mat-icon>
|
||||||
|
<h4 matLine>Accounting Rules</h4>
|
||||||
|
<p matLine>List of all accounting rules</p>
|
||||||
|
</mat-list-item>
|
||||||
|
|
||||||
|
<mat-list-item [routerLink]="['periodic-accruals']">
|
||||||
|
<mat-icon matListIcon>
|
||||||
|
<fa-icon icon="calendar" size="sm"></fa-icon>
|
||||||
|
</mat-icon>
|
||||||
|
<h4 matLine>Accruals</h4>
|
||||||
|
<p matLine>Accrues income, expenses and liabilities as on the provided date</p>
|
||||||
|
</mat-list-item>
|
||||||
|
|
||||||
|
<mat-list-item [routerLink]="['provisioning-entries']">
|
||||||
|
<mat-icon matListIcon>
|
||||||
|
<fa-icon icon="cogs" size="sm"></fa-icon>
|
||||||
|
</mat-icon>
|
||||||
|
<h4 matLine>Provisioning Entries</h4>
|
||||||
|
<p matLine>Create provisioning entries</p>
|
||||||
|
</mat-list-item>
|
||||||
|
|
||||||
|
</mat-nav-list>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div fxFlex="50%">
|
</mat-card>
|
||||||
|
|
||||||
<mat-nav-list>
|
|
||||||
|
|
||||||
<mat-list-item [routerLink]="['/accounting/chart-of-accounts']">
|
|
||||||
<mat-icon matListIcon>device_hub</mat-icon>
|
|
||||||
<h4 matLine>Chart of Accounts</h4>
|
|
||||||
<p matLine>List of accounts used by the organisation</p>
|
|
||||||
</mat-list-item>
|
|
||||||
|
|
||||||
<mat-list-item [routerLink]="['/accounting/closing-entries']">
|
|
||||||
<mat-icon matListIcon>archive</mat-icon>
|
|
||||||
<h4 matLine>Closing Entries</h4>
|
|
||||||
<p matLine>Journal entries made at the end of accounting period</p>
|
|
||||||
</mat-list-item>
|
|
||||||
|
|
||||||
<mat-list-item [routerLink]="['/accounting/accounting-rules']">
|
|
||||||
<mat-icon matListIcon>list</mat-icon>
|
|
||||||
<h4 matLine>Accounting Rules</h4>
|
|
||||||
<p matLine>List of all accounting rules</p>
|
|
||||||
</mat-list-item>
|
|
||||||
|
|
||||||
<mat-list-item [routerLink]="['/accounting/periodic-accruals']">
|
|
||||||
<mat-icon matListIcon>calendar_today</mat-icon>
|
|
||||||
<h4 matLine>Accruals</h4>
|
|
||||||
<p matLine>Accrues income, expenses and liabilities as on the provided date</p>
|
|
||||||
</mat-list-item>
|
|
||||||
|
|
||||||
<mat-list-item [routerLink]="['/accounting/provisioning-entries']">
|
|
||||||
<mat-icon matListIcon>settings_backup_restore</mat-icon>
|
|
||||||
<h4 matLine>Provisioning Entries</h4>
|
|
||||||
<p matLine>Create provisioning entries</p>
|
|
||||||
</mat-list-item>
|
|
||||||
|
|
||||||
</mat-nav-list>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</mat-card>
|
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|||||||
@@ -1,5 +1,9 @@
|
|||||||
|
/** Angular Imports */
|
||||||
import { Component, OnInit } from '@angular/core';
|
import { Component, OnInit } from '@angular/core';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Accounting component.
|
||||||
|
*/
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'mifosx-accounting',
|
selector: 'mifosx-accounting',
|
||||||
templateUrl: './accounting.component.html',
|
templateUrl: './accounting.component.html',
|
||||||
|
|||||||
@@ -1,22 +1,24 @@
|
|||||||
|
/** Angular Imports */
|
||||||
import { NgModule } from '@angular/core';
|
import { NgModule } from '@angular/core';
|
||||||
import { CommonModule } from '@angular/common';
|
|
||||||
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
|
|
||||||
|
|
||||||
import { CoreModule } from '../core/core.module';
|
/** Custom Modules */
|
||||||
import { AccountingComponent } from './accounting.component';
|
import { SharedModule } from '../shared/shared.module';
|
||||||
import { AccountingRoutingModule } from './accounting-routing.module';
|
import { AccountingRoutingModule } from './accounting-routing.module';
|
||||||
|
|
||||||
|
/** Custom Components */
|
||||||
|
import { AccountingComponent } from './accounting.component';
|
||||||
import { FrequentPostingsComponent } from './frequent-postings/frequent-postings.component';
|
import { FrequentPostingsComponent } from './frequent-postings/frequent-postings.component';
|
||||||
|
import { CreateJournalEntryComponent } from './create-journal-entry/create-journal-entry.component';
|
||||||
|
import { SearchJournalEntryComponent } from './search-journal-entry/search-journal-entry.component';
|
||||||
import { ViewTransactionComponent } from './view-transaction/view-transaction.component';
|
import { ViewTransactionComponent } from './view-transaction/view-transaction.component';
|
||||||
import { RevertTransactionComponent } from './revert-transaction/revert-transaction.component';
|
import { RevertTransactionComponent } from './revert-transaction/revert-transaction.component';
|
||||||
import { ViewJournalEntryComponent } from './view-journal-entry/view-journal-entry.component';
|
import { ViewJournalEntryComponent } from './view-journal-entry/view-journal-entry.component';
|
||||||
import { CreateJournalEntryComponent } from './create-journal-entry/create-journal-entry.component';
|
|
||||||
import { SearchJournalEntryComponent } from './search-journal-entry/search-journal-entry.component';
|
|
||||||
import { FinancialActivityMappingsComponent } from './financial-activity-mappings/financial-activity-mappings.component';
|
import { FinancialActivityMappingsComponent } from './financial-activity-mappings/financial-activity-mappings.component';
|
||||||
import { CreateFinancialActivityMappingComponent } from './financial-activity-mappings/create-financial-activity-mapping/create-financial-activity-mapping.component';
|
import { CreateFinancialActivityMappingComponent } from './financial-activity-mappings/create-financial-activity-mapping/create-financial-activity-mapping.component';
|
||||||
import { ViewFinancialActivityMappingComponent } from './financial-activity-mappings/view-financial-activity-mapping/view-financial-activity-mapping.component';
|
import { ViewFinancialActivityMappingComponent } from './financial-activity-mappings/view-financial-activity-mapping/view-financial-activity-mapping.component';
|
||||||
import { EditFinancialActivityMappingComponent } from './financial-activity-mappings/edit-financial-activity-mapping/edit-financial-activity-mapping.component';
|
import { EditFinancialActivityMappingComponent } from './financial-activity-mappings/edit-financial-activity-mapping/edit-financial-activity-mapping.component';
|
||||||
|
import { MigrateOpeningBalancesComponent } from './migrate-opening-balances/migrate-opening-balances.component';
|
||||||
import { ChartOfAccountsComponent } from './chart-of-accounts/chart-of-accounts.component';
|
import { ChartOfAccountsComponent } from './chart-of-accounts/chart-of-accounts.component';
|
||||||
|
|
||||||
import { CreateGlAccountComponent } from './chart-of-accounts/create-gl-account/create-gl-account.component';
|
import { CreateGlAccountComponent } from './chart-of-accounts/create-gl-account/create-gl-account.component';
|
||||||
import { ViewGlAccountComponent } from './chart-of-accounts/view-gl-account/view-gl-account.component';
|
import { ViewGlAccountComponent } from './chart-of-accounts/view-gl-account/view-gl-account.component';
|
||||||
import { EditGlAccountComponent } from './chart-of-accounts/edit-gl-account/edit-gl-account.component';
|
import { EditGlAccountComponent } from './chart-of-accounts/edit-gl-account/edit-gl-account.component';
|
||||||
@@ -33,28 +35,30 @@ import { ProvisioningEntriesComponent } from './provisioning-entries/provisionin
|
|||||||
import { CreateProvisioningEntryComponent } from './provisioning-entries/create-provisioning-entry/create-provisioning-entry.component';
|
import { CreateProvisioningEntryComponent } from './provisioning-entries/create-provisioning-entry/create-provisioning-entry.component';
|
||||||
import { ViewProvisioningEntryComponent } from './provisioning-entries/view-provisioning-entry/view-provisioning-entry.component';
|
import { ViewProvisioningEntryComponent } from './provisioning-entries/view-provisioning-entry/view-provisioning-entry.component';
|
||||||
import { ViewProvisioningJournalEntriesComponent } from './provisioning-entries/view-provisioning-journal-entries/view-provisioning-journal-entries.component';
|
import { ViewProvisioningJournalEntriesComponent } from './provisioning-entries/view-provisioning-journal-entries/view-provisioning-journal-entries.component';
|
||||||
import { MigrateOpeningBalancesComponent } from './migrate-opening-balances/migrate-opening-balances.component';
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Accounting Module
|
||||||
|
*
|
||||||
|
* All components related to accounting functions should be declared here.
|
||||||
|
*/
|
||||||
@NgModule({
|
@NgModule({
|
||||||
imports: [
|
imports: [
|
||||||
CoreModule,
|
SharedModule,
|
||||||
CommonModule,
|
|
||||||
FormsModule,
|
|
||||||
ReactiveFormsModule,
|
|
||||||
AccountingRoutingModule
|
AccountingRoutingModule
|
||||||
],
|
],
|
||||||
declarations: [
|
declarations: [
|
||||||
AccountingComponent,
|
AccountingComponent,
|
||||||
FrequentPostingsComponent,
|
FrequentPostingsComponent,
|
||||||
|
CreateJournalEntryComponent,
|
||||||
|
SearchJournalEntryComponent,
|
||||||
ViewTransactionComponent,
|
ViewTransactionComponent,
|
||||||
RevertTransactionComponent,
|
RevertTransactionComponent,
|
||||||
ViewJournalEntryComponent,
|
ViewJournalEntryComponent,
|
||||||
CreateJournalEntryComponent,
|
|
||||||
SearchJournalEntryComponent,
|
|
||||||
FinancialActivityMappingsComponent,
|
FinancialActivityMappingsComponent,
|
||||||
CreateFinancialActivityMappingComponent,
|
CreateFinancialActivityMappingComponent,
|
||||||
ViewFinancialActivityMappingComponent,
|
ViewFinancialActivityMappingComponent,
|
||||||
EditFinancialActivityMappingComponent,
|
EditFinancialActivityMappingComponent,
|
||||||
|
MigrateOpeningBalancesComponent,
|
||||||
ChartOfAccountsComponent,
|
ChartOfAccountsComponent,
|
||||||
CreateGlAccountComponent,
|
CreateGlAccountComponent,
|
||||||
ViewGlAccountComponent,
|
ViewGlAccountComponent,
|
||||||
@@ -71,8 +75,7 @@ import { MigrateOpeningBalancesComponent } from './migrate-opening-balances/migr
|
|||||||
ProvisioningEntriesComponent,
|
ProvisioningEntriesComponent,
|
||||||
CreateProvisioningEntryComponent,
|
CreateProvisioningEntryComponent,
|
||||||
ViewProvisioningEntryComponent,
|
ViewProvisioningEntryComponent,
|
||||||
ViewProvisioningJournalEntriesComponent,
|
ViewProvisioningJournalEntriesComponent
|
||||||
MigrateOpeningBalancesComponent
|
|
||||||
],
|
],
|
||||||
entryComponents: [
|
entryComponents: [
|
||||||
RevertTransactionComponent,
|
RevertTransactionComponent,
|
||||||
|
|||||||
@@ -1,19 +1,38 @@
|
|||||||
|
/** TODO: Separate services for feature modules for cleaner accounting service. */
|
||||||
|
|
||||||
|
/** Angular Imports */
|
||||||
import { Injectable } from '@angular/core';
|
import { Injectable } from '@angular/core';
|
||||||
import { HttpClient, HttpParams } from '@angular/common/http';
|
import { HttpClient, HttpParams } from '@angular/common/http';
|
||||||
|
|
||||||
|
/** rxjs Imports */
|
||||||
import { Observable } from 'rxjs';
|
import { Observable } from 'rxjs';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Accounting service.
|
||||||
|
*/
|
||||||
@Injectable({
|
@Injectable({
|
||||||
providedIn: 'root'
|
providedIn: 'root'
|
||||||
})
|
})
|
||||||
export class AccountingService {
|
export class AccountingService {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {HttpClient} http Http Client to send requests.
|
||||||
|
*/
|
||||||
constructor(private http: HttpClient) { }
|
constructor(private http: HttpClient) { }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @returns {Observable<any>} Offices data ordered by id.
|
||||||
|
*/
|
||||||
getOffices(): Observable<any> {
|
getOffices(): Observable<any> {
|
||||||
return this.http.get('/offices?orderBy=id');
|
const httpParams = new HttpParams().set('orderBy', 'id');
|
||||||
|
return this.http.get('/offices', { params: httpParams });
|
||||||
}
|
}
|
||||||
|
|
||||||
getAccountingRules(useHttpParams?: boolean): Observable<any> {
|
/**
|
||||||
|
* @param {boolean} useHttpParams True if http params should be used.
|
||||||
|
* @returns {Observable<any>} Accounting rules data.
|
||||||
|
*/
|
||||||
|
getAccountingRules(useHttpParams: boolean = false): Observable<any> {
|
||||||
let httpParams = new HttpParams();
|
let httpParams = new HttpParams();
|
||||||
if (useHttpParams) {
|
if (useHttpParams) {
|
||||||
httpParams = httpParams.set('associations', 'all');
|
httpParams = httpParams.set('associations', 'all');
|
||||||
@@ -21,45 +40,80 @@ export class AccountingService {
|
|||||||
return this.http.get('/accountingrules', { params: httpParams });
|
return this.http.get('/accountingrules', { params: httpParams });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @returns {Observable<any>} Currencies data.
|
||||||
|
*/
|
||||||
getCurrencies(): Observable<any> {
|
getCurrencies(): Observable<any> {
|
||||||
return this.http.get('/currencies');
|
return this.http.get('/currencies');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @returns {Observable<any>} Payment types data.
|
||||||
|
*/
|
||||||
getPaymentTypes(): Observable<any> {
|
getPaymentTypes(): Observable<any> {
|
||||||
return this.http.get('/paymenttypes');
|
return this.http.get('/paymenttypes');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {any} journalEntry Journal entry to be created.
|
||||||
|
* @returns {Observable<any>}
|
||||||
|
*/
|
||||||
createJournalEntry(journalEntry: any): Observable<any> {
|
createJournalEntry(journalEntry: any): Observable<any> {
|
||||||
return this.http.post('/journalentries', journalEntry);
|
return this.http.post('/journalentries', journalEntry);
|
||||||
}
|
}
|
||||||
|
|
||||||
getJournalEntry(transactionId: string) {
|
/**
|
||||||
let httpParams = new HttpParams();
|
* @returns {Observable<any>} GL Accounts.
|
||||||
httpParams = httpParams.set('transactionId', transactionId);
|
*/
|
||||||
httpParams = httpParams.set('transactionDetails', 'true');
|
getGlAccounts(): Observable<any> {
|
||||||
|
const httpParams = new HttpParams()
|
||||||
|
.set('manualEntriesAllowed', 'true')
|
||||||
|
.set('usage', '1')
|
||||||
|
.set('disabled', 'false');
|
||||||
|
return this.http.get(`/glaccounts`, { params: httpParams });
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param transactionId Transaction ID of journal entries.
|
||||||
|
* @returns {Observable<any>} Journal Entries.
|
||||||
|
*/
|
||||||
|
getJournalEntry(transactionId: string): Observable<any> {
|
||||||
|
const httpParams = new HttpParams()
|
||||||
|
.set('transactionId', transactionId)
|
||||||
|
.set('transactionDetails', 'true');
|
||||||
return this.http.get(`/journalentries`, { params: httpParams });
|
return this.http.get(`/journalentries`, { params: httpParams });
|
||||||
}
|
}
|
||||||
|
|
||||||
// filterBy: officeId, glAccountId, manualEntriesOnly, fromDate, toDate, transactionId
|
/**
|
||||||
getJournalEntries(filterBy: any, orderBy: string, sortOrder: string, offset: number, limit: number) {
|
* @param {any} filterBy Properties by which entries should be filtered.
|
||||||
|
* @param {string} orderBy Property by which entries should be sorted.
|
||||||
|
* @param {string} sortOrder Sort order: ascending or descending.
|
||||||
|
* @param {number} offset Page offset.
|
||||||
|
* @param {number} limit Number of entries within the page.
|
||||||
|
* @returns {Observable<any>} Journal Entries.
|
||||||
|
*/
|
||||||
|
getJournalEntries(filterBy: any, orderBy: string, sortOrder: string, offset: number, limit: number): Observable<any> {
|
||||||
let httpParams = new HttpParams()
|
let httpParams = new HttpParams()
|
||||||
.set('offset', offset.toString())
|
.set('offset', offset.toString())
|
||||||
.set('limit', limit.toString())
|
.set('limit', limit.toString())
|
||||||
.set('sortOrder', sortOrder)
|
.set('sortOrder', sortOrder)
|
||||||
.set('orderBy', orderBy);
|
.set('orderBy', orderBy);
|
||||||
|
// filterBy: officeId, glAccountId, manualEntriesOnly, fromDate, toDate, transactionId
|
||||||
filterBy.forEach(function (filter: any) {
|
filterBy.forEach(function (filter: any) {
|
||||||
if (filter.value) {
|
if (filter.value) {
|
||||||
httpParams = httpParams.set(filter.type, filter.value);
|
httpParams = httpParams.set(filter.type, filter.value);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return this.http.get('/journalentries', {
|
return this.http.get('/journalentries', { params: httpParams });
|
||||||
params: httpParams
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
revertTransaction(transactionId: string, comments: string) {
|
/**
|
||||||
let httpParams = new HttpParams();
|
* @param {string} transactionId Transaction ID to be reverted.
|
||||||
httpParams = httpParams.set('command', 'reverse');
|
* @param {string} comments Any comments.
|
||||||
|
* @returns {Observable<any>}
|
||||||
|
*/
|
||||||
|
revertTransaction(transactionId: string, comments: string): Observable<any> {
|
||||||
|
const httpParams = new HttpParams().set('command', 'reverse');
|
||||||
let data = {};
|
let data = {};
|
||||||
if (comments) {
|
if (comments) {
|
||||||
data = { comments: comments };
|
data = { comments: comments };
|
||||||
@@ -67,158 +121,281 @@ export class AccountingService {
|
|||||||
return this.http.post(`/journalentries/${transactionId}`, data, { params: httpParams });
|
return this.http.post(`/journalentries/${transactionId}`, data, { params: httpParams });
|
||||||
}
|
}
|
||||||
|
|
||||||
getGlAccounts() {
|
/**
|
||||||
let httpParams = new HttpParams();
|
* @returns {Observable<any>} Financial activity accounts.
|
||||||
httpParams = httpParams.set('manualEntriesAllowed', 'true');
|
*/
|
||||||
httpParams = httpParams.set('usage', '1');
|
getFinancialActivityAccounts(): Observable<any> {
|
||||||
httpParams = httpParams.set('disabled', 'false');
|
|
||||||
return this.http.get(`/glaccounts`, { params: httpParams });
|
|
||||||
}
|
|
||||||
|
|
||||||
getFinancialActivityAccounts() {
|
|
||||||
return this.http.get('/financialactivityaccounts');
|
return this.http.get('/financialactivityaccounts');
|
||||||
}
|
}
|
||||||
|
|
||||||
getFinancialActivityAccountsTemplate() {
|
/**
|
||||||
|
* @returns {Observable<any>} Financial activity accounts template.
|
||||||
|
*/
|
||||||
|
getFinancialActivityAccountsTemplate(): Observable<any> {
|
||||||
return this.http.get('/financialactivityaccounts/template');
|
return this.http.get('/financialactivityaccounts/template');
|
||||||
}
|
}
|
||||||
|
|
||||||
createFinancialActivityAccount(financialActivityAccount: any) {
|
/**
|
||||||
|
* @param {any} financialActivityAccount Financial activity account to be created.
|
||||||
|
* @returns {Observable<any>}
|
||||||
|
*/
|
||||||
|
createFinancialActivityAccount(financialActivityAccount: any): Observable<any> {
|
||||||
return this.http.post('/financialactivityaccounts', financialActivityAccount);
|
return this.http.post('/financialactivityaccounts', financialActivityAccount);
|
||||||
}
|
}
|
||||||
|
|
||||||
getFinancialActivityAccount(financialActivityAccountId: number, template: boolean) {
|
/**
|
||||||
|
* @param {string} financialActivityAccountId Financial activity account ID of financial activity account.
|
||||||
|
* @param {boolean} template True if template is required.
|
||||||
|
* @returns {Observable<any>} Financial activity account.
|
||||||
|
*/
|
||||||
|
getFinancialActivityAccount(financialActivityAccountId: string, template: boolean = false): Observable<any> {
|
||||||
const httpParams = new HttpParams().set('template', template.toString());
|
const httpParams = new HttpParams().set('template', template.toString());
|
||||||
return this.http.get(`/financialactivityaccounts/${financialActivityAccountId}`, { params: httpParams });
|
return this.http.get(`/financialactivityaccounts/${financialActivityAccountId}`, { params: httpParams });
|
||||||
}
|
}
|
||||||
|
|
||||||
updateFinancialActivityAccount(financialActivityAccountId: number, financialActivityAccount: any) {
|
/**
|
||||||
|
* @param {string} financialActivityAccountId Financial activity account ID of financial activity account to be updated.
|
||||||
|
* @param {any} financialActivityAccount Financial activity account to be updated.
|
||||||
|
* @returns {Observable<any>}
|
||||||
|
*/
|
||||||
|
updateFinancialActivityAccount(financialActivityAccountId: string, financialActivityAccount: any): Observable<any> {
|
||||||
return this.http.put(`/financialactivityaccounts/${financialActivityAccountId}`, financialActivityAccount);
|
return this.http.put(`/financialactivityaccounts/${financialActivityAccountId}`, financialActivityAccount);
|
||||||
}
|
}
|
||||||
|
|
||||||
deleteFinancialActivityAccount(financialActivityAccountId: number) {
|
/**
|
||||||
|
* @param {string} financialActivityAccountId Financial activity account ID of financial activity account to be deleted.
|
||||||
|
* @returns {Observable<any>}
|
||||||
|
*/
|
||||||
|
deleteFinancialActivityAccount(financialActivityAccountId: string): Observable<any> {
|
||||||
return this.http.delete(`/financialactivityaccounts/${financialActivityAccountId}`);
|
return this.http.delete(`/financialactivityaccounts/${financialActivityAccountId}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
getChartOfAccounts() {
|
/**
|
||||||
|
* @param {string} officeId Office ID to retrive opening balances accounts for.
|
||||||
|
* @returns {Observable<any>}
|
||||||
|
*/
|
||||||
|
retrieveOpeningBalances(officeId: string): Observable<any> {
|
||||||
|
const httpParams = new HttpParams().set('officeId', officeId);
|
||||||
|
return this.http.get('/journalentries/openingbalance', { params: httpParams });
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {any} openingBalances Opening balances for office accounts to be defined.
|
||||||
|
* @returns {Observable<any>}
|
||||||
|
*/
|
||||||
|
defineOpeningBalances(openingBalances: any): Observable<any> {
|
||||||
|
const httpParams = new HttpParams().set('command', 'defineOpeningBalance');
|
||||||
|
return this.http.post(`/journalentries`, openingBalances, { params: httpParams });
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @returns {Observable<any>} GL accounts.
|
||||||
|
*/
|
||||||
|
getChartOfAccounts(): Observable<any> {
|
||||||
return this.http.get('/glaccounts');
|
return this.http.get('/glaccounts');
|
||||||
}
|
}
|
||||||
|
|
||||||
getChartOfAccountsTemplate() {
|
/**
|
||||||
|
* @returns {Observable<any>} GL accounts template.
|
||||||
|
*/
|
||||||
|
getChartOfAccountsTemplate(): Observable<any> {
|
||||||
return this.http.get('/glaccounts/template');
|
return this.http.get('/glaccounts/template');
|
||||||
}
|
}
|
||||||
|
|
||||||
createGlAccount(glAccount: any) {
|
/**
|
||||||
|
* @param {any} glAccount GL account to be created.
|
||||||
|
* @returns {Observable<any>}
|
||||||
|
*/
|
||||||
|
createGlAccount(glAccount: any): Observable<any> {
|
||||||
return this.http.post('/glaccounts', glAccount);
|
return this.http.post('/glaccounts', glAccount);
|
||||||
}
|
}
|
||||||
|
|
||||||
getGlAccount(glAccountId: string, template: boolean = false) {
|
/**
|
||||||
|
* @param {string} glAccountId GL account ID of gl account.
|
||||||
|
* @param {boolean} template True if template is required.
|
||||||
|
* @returns {Observable<any>} GL account.
|
||||||
|
*/
|
||||||
|
getGlAccount(glAccountId: string, template: boolean = false): Observable<any> {
|
||||||
const httpParams = new HttpParams().set('template', template.toString());
|
const httpParams = new HttpParams().set('template', template.toString());
|
||||||
return this.http.get(`/glaccounts/${glAccountId}`, { params: httpParams });
|
return this.http.get(`/glaccounts/${glAccountId}`, { params: httpParams });
|
||||||
}
|
}
|
||||||
|
|
||||||
updateGlAccount(glAccountId: number, glAccount: any) {
|
/**
|
||||||
|
* @param {string} glAccountId GL account ID of gl account.
|
||||||
|
* @param {any} glAccount GL account to be updated.
|
||||||
|
* @returns {Observable<any>}
|
||||||
|
*/
|
||||||
|
updateGlAccount(glAccountId: string, glAccount: any): Observable<any> {
|
||||||
return this.http.put(`/glaccounts/${glAccountId}`, glAccount);
|
return this.http.put(`/glaccounts/${glAccountId}`, glAccount);
|
||||||
}
|
}
|
||||||
|
|
||||||
deleteGlAccount(glAccountId: number) {
|
/**
|
||||||
|
* @param glAccountId GL account ID of gl account to be deleted.
|
||||||
|
* @returns {Observable<any>}
|
||||||
|
*/
|
||||||
|
deleteGlAccount(glAccountId: string): Observable<any> {
|
||||||
return this.http.delete(`/glaccounts/${glAccountId}`);
|
return this.http.delete(`/glaccounts/${glAccountId}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
getAccountingClosures() {
|
/**
|
||||||
|
* @returns {Observable<any>} GL account closures.
|
||||||
|
*/
|
||||||
|
getAccountingClosures(): Observable<any> {
|
||||||
return this.http.get('/glclosures');
|
return this.http.get('/glclosures');
|
||||||
}
|
}
|
||||||
|
|
||||||
createAccountingClosure(accountingClosure: any) {
|
/**
|
||||||
|
* @param {any} accountingClosure GL closure to be created.
|
||||||
|
* @returns {Observable<any>}
|
||||||
|
*/
|
||||||
|
createAccountingClosure(accountingClosure: any): Observable<any> {
|
||||||
return this.http.post('/glclosures', accountingClosure);
|
return this.http.post('/glclosures', accountingClosure);
|
||||||
}
|
}
|
||||||
|
|
||||||
getAccountingClosure(accountingClosureId: number) {
|
/**
|
||||||
|
* @param {string} accountingClosureId Accounting closure ID of gl closure.
|
||||||
|
* @returns {Observable<any>} Accounting closure.
|
||||||
|
*/
|
||||||
|
getAccountingClosure(accountingClosureId: string): Observable<any> {
|
||||||
return this.http.get(`/glclosures/${accountingClosureId}`);
|
return this.http.get(`/glclosures/${accountingClosureId}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
deleteAccountingClosure(accountingClosureId: number) {
|
/**
|
||||||
return this.http.delete(`/glclosures/${accountingClosureId}`);
|
* @param {string} accountingClosureId Accounting closure ID of gl closure to be updated.
|
||||||
}
|
* @param {any} accountingClosure Accounting closure to be updated.
|
||||||
|
* @returns {Observable<any>}
|
||||||
updateAccountingClosure(accountingClosureId: number, accountingClosure: any) {
|
*/
|
||||||
|
updateAccountingClosure(accountingClosureId: string, accountingClosure: any): Observable<any> {
|
||||||
return this.http.put(`/glclosures/${accountingClosureId}`, accountingClosure);
|
return this.http.put(`/glclosures/${accountingClosureId}`, accountingClosure);
|
||||||
}
|
}
|
||||||
|
|
||||||
getAccountingRulesTemplate() {
|
/**
|
||||||
|
* @param {string} accountingClosureId Accounting closure ID of gl closure to be deleted.
|
||||||
|
* @returns {Observable<any>}
|
||||||
|
*/
|
||||||
|
deleteAccountingClosure(accountingClosureId: string): Observable<any> {
|
||||||
|
return this.http.delete(`/glclosures/${accountingClosureId}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @returns {Observable<any>} Accounting rules template.
|
||||||
|
*/
|
||||||
|
getAccountingRulesTemplate(): Observable<any> {
|
||||||
return this.http.get('/accountingrules/template');
|
return this.http.get('/accountingrules/template');
|
||||||
}
|
}
|
||||||
|
|
||||||
createAccountingRule(accountingRule: any) {
|
/**
|
||||||
|
* @param {any} accountingRule Accounting rule to be created.
|
||||||
|
* @returns {Observable<any>}
|
||||||
|
*/
|
||||||
|
createAccountingRule(accountingRule: any): Observable<any> {
|
||||||
return this.http.post('/accountingrules', accountingRule);
|
return this.http.post('/accountingrules', accountingRule);
|
||||||
}
|
}
|
||||||
|
|
||||||
getAccountingRule(accountingRuleId: string) {
|
/**
|
||||||
|
* @param {string} accountingRuleId Accounting rule ID of accounting rule.
|
||||||
|
* @returns {Observable<any>} Accounting rule.
|
||||||
|
*/
|
||||||
|
getAccountingRule(accountingRuleId: string): Observable<any> {
|
||||||
return this.http.get(`/accountingrules/${accountingRuleId}`);
|
return this.http.get(`/accountingrules/${accountingRuleId}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
deleteAccountingRule(accountingRuleId: number) {
|
/**
|
||||||
return this.http.delete(`/accountingrules/${accountingRuleId}`);
|
* @param {string} accoutingRuleId Accounting rule ID of accounting rule to be updated.
|
||||||
}
|
* @param {any} accountingRule Accounting rule to be updated.
|
||||||
|
* @returns {Observable<any>}
|
||||||
updateAccountingRule(accoutingRuleId: number, accountingRule: any) {
|
*/
|
||||||
|
updateAccountingRule(accoutingRuleId: string, accountingRule: any): Observable<any> {
|
||||||
return this.http.put(`/accountingrules/${accoutingRuleId}`, accountingRule);
|
return this.http.put(`/accountingrules/${accoutingRuleId}`, accountingRule);
|
||||||
}
|
}
|
||||||
|
|
||||||
executePeriodicAccruals(periodicAccruals: any) {
|
/**
|
||||||
|
* @param {string} accountingRuleId Accounting rule ID of accounting rule to be deleted.
|
||||||
|
* @returns {Observable<any>}
|
||||||
|
*/
|
||||||
|
deleteAccountingRule(accountingRuleId: string): Observable<any> {
|
||||||
|
return this.http.delete(`/accountingrules/${accountingRuleId}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {any} periodicAccruals Accruals to be executed.
|
||||||
|
* @returns {Observable<any>}
|
||||||
|
*/
|
||||||
|
executePeriodicAccruals(periodicAccruals: any): Observable<any> {
|
||||||
return this.http.post('/runaccruals', periodicAccruals);
|
return this.http.post('/runaccruals', periodicAccruals);
|
||||||
}
|
}
|
||||||
|
|
||||||
getProvisioningEntries() {
|
/**
|
||||||
|
* @returns {Observable<any>} Provisioning entries.
|
||||||
|
*/
|
||||||
|
getProvisioningEntries(): Observable<any> {
|
||||||
return this.http.get('/provisioningentries');
|
return this.http.get('/provisioningentries');
|
||||||
}
|
}
|
||||||
|
|
||||||
createProvisioningEntry(provisioningEntry: any) {
|
/**
|
||||||
|
* @param {any} provisioningEntry Provisioning entry to be created.
|
||||||
|
* @returns {Observable<any>}
|
||||||
|
*/
|
||||||
|
createProvisioningEntry(provisioningEntry: any): Observable<any> {
|
||||||
return this.http.post('/provisioningentries', provisioningEntry);
|
return this.http.post('/provisioningentries', provisioningEntry);
|
||||||
}
|
}
|
||||||
|
|
||||||
getProvisioningEntry(provisioningEntryId: string) {
|
/**
|
||||||
|
* @param {string} provisioningEntryId Provisioning entry ID of provisioning entry.
|
||||||
|
* @returns {Observable<any>} Provisioning entry.
|
||||||
|
*/
|
||||||
|
getProvisioningEntry(provisioningEntryId: string): Observable<any> {
|
||||||
return this.http.get(`/provisioningentries/${provisioningEntryId}`);
|
return this.http.get(`/provisioningentries/${provisioningEntryId}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
getLoanProducts() {
|
/**
|
||||||
|
* @returns {Observable<any>} Loan products data.
|
||||||
|
*/
|
||||||
|
getLoanProducts(): Observable<any> {
|
||||||
return this.http.get('/loanproducts');
|
return this.http.get('/loanproducts');
|
||||||
}
|
}
|
||||||
|
|
||||||
getProvisioningCategories() {
|
/**
|
||||||
|
* @returns {Observable<any>} Provisioning categories data.
|
||||||
|
*/
|
||||||
|
getProvisioningCategories(): Observable<any> {
|
||||||
return this.http.get('/provisioningcategory');
|
return this.http.get('/provisioningcategory');
|
||||||
}
|
}
|
||||||
|
|
||||||
getProvisioningEntryEntries(entryId: string) {
|
/**
|
||||||
const httpParams = new HttpParams().set('entryId', entryId);
|
* @param {string} provisioningEntryId Provisioning entry ID of provisioning entry.
|
||||||
|
* @returns {Observable<any>} Provisioning entry entries.
|
||||||
|
*/
|
||||||
|
getProvisioningEntryEntries(provisioningEntryId: string): Observable<any> {
|
||||||
|
const httpParams = new HttpParams().set('entryId', provisioningEntryId);
|
||||||
return this.http.get('/provisioningentries/entries', { params: httpParams });
|
return this.http.get('/provisioningentries/entries', { params: httpParams });
|
||||||
}
|
}
|
||||||
|
|
||||||
getProvisioningJournalEntries(entryId: string) {
|
/**
|
||||||
const httpParams = new HttpParams().set('entryId', entryId);
|
* @param {string} provisioningEntryId Provisioning entry ID of provisioning entry.
|
||||||
|
* @returns {Observable<any>} Provisioning journal entries.
|
||||||
|
*/
|
||||||
|
getProvisioningJournalEntries(provisioningEntryId: string): Observable<any> {
|
||||||
|
const httpParams = new HttpParams().set('entryId', provisioningEntryId);
|
||||||
return this.http.get('/journalentries/provisioning', { params: httpParams });
|
return this.http.get('/journalentries/provisioning', { params: httpParams });
|
||||||
}
|
}
|
||||||
|
|
||||||
createProvisioningJournalEntries(provisioningEntryId: string) {
|
/**
|
||||||
|
* @param {string} provisioningEntryId Provisioning entry ID for which journal entries need to be created.
|
||||||
|
* @returns {Observable<any>}
|
||||||
|
*/
|
||||||
|
createProvisioningJournalEntries(provisioningEntryId: string): Observable<any> {
|
||||||
const httpParams = new HttpParams().set('command', 'createjournalentry');
|
const httpParams = new HttpParams().set('command', 'createjournalentry');
|
||||||
return this.http.post(`/provisioningentries/${provisioningEntryId}`, {}, { params: httpParams });
|
return this.http.post(`/provisioningentries/${provisioningEntryId}`, {}, { params: httpParams });
|
||||||
}
|
}
|
||||||
|
|
||||||
recreateProvisioningEntries(provisioningEntryId: string) {
|
/**
|
||||||
|
* @param {string} provisioningEntryId Provisioning entry ID for which provisioning entry needs to be recreated.
|
||||||
|
* @returns {Observable<any>}
|
||||||
|
*/
|
||||||
|
recreateProvisioningEntries(provisioningEntryId: string): Observable<any> {
|
||||||
const httpParams = new HttpParams().set('command', 'recreateprovisioningentry');
|
const httpParams = new HttpParams().set('command', 'recreateprovisioningentry');
|
||||||
return this.http.post(`/provisioningentries/${provisioningEntryId}`, {}, { params: httpParams });
|
return this.http.post(`/provisioningentries/${provisioningEntryId}`, {}, { params: httpParams });
|
||||||
}
|
}
|
||||||
|
|
||||||
retrieveOpeningBalances(officeId: number) {
|
|
||||||
let httpParams = new HttpParams();
|
|
||||||
httpParams = httpParams.set('officeId', officeId.toString());
|
|
||||||
return this.http.get('/journalentries/openingbalance', { params: httpParams });
|
|
||||||
}
|
|
||||||
|
|
||||||
defineOpeningBalances(openingBalances: any) {
|
|
||||||
let httpParams = new HttpParams();
|
|
||||||
httpParams = httpParams.set('command', 'defineOpeningBalance');
|
|
||||||
return this.http.post(`/journalentries`, openingBalances, { params: httpParams });
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,25 +1,27 @@
|
|||||||
<div class="container m-b-20" fxLayout="row" fxLayoutAlign="end" fxLayoutGap="20px">
|
<div class="container m-b-20" fxLayout="row" fxLayoutAlign="end" fxLayoutGap="20px">
|
||||||
<mat-button-toggle-group [formControl]="viewGroup">
|
<mat-button-toggle-group [formControl]="viewGroup">
|
||||||
<mat-button-toggle value="listView">
|
<mat-button-toggle value="listView">
|
||||||
<mat-icon>list</mat-icon>
|
<fa-icon icon="list"></fa-icon>
|
||||||
</mat-button-toggle>
|
</mat-button-toggle>
|
||||||
<mat-button-toggle value="treeView">
|
<mat-button-toggle value="treeView">
|
||||||
<mat-icon>device_hub</mat-icon>
|
<fa-icon icon="sitemap"></fa-icon>
|
||||||
</mat-button-toggle>
|
</mat-button-toggle>
|
||||||
</mat-button-toggle-group>
|
</mat-button-toggle-group>
|
||||||
<button mat-raised-button color="primary" [routerLink]="['/accounting/chart-of-accounts/gl-accounts/create']">
|
<button mat-raised-button color="primary" [routerLink]="['gl-accounts/create']">
|
||||||
<mat-icon>add</mat-icon> Add Account
|
<fa-icon icon="plus"></fa-icon>
|
||||||
|
Add Account
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
<!-- List View -->
|
<!-- List View -->
|
||||||
|
|
||||||
<div class="container" *ngIf="viewGroup.value === 'listView'">
|
<div class="container" [hidden]="viewGroup.value !== 'listView'">
|
||||||
|
|
||||||
<div fxLayout="row" fxLayoutGap="20px">
|
<div fxLayout="row" fxLayoutGap="20px">
|
||||||
<mat-form-field fxFlex>
|
<mat-form-field fxFlex>
|
||||||
<input matInput (keyup)="applyFilter($event.target.value)" placeholder="Filter">
|
<mat-label>Filter</mat-label>
|
||||||
|
<input matInput (keyup)="applyFilter($event.target.value)">
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -46,7 +48,7 @@
|
|||||||
<th mat-header-cell *matHeaderCellDef mat-sort-header> Disabled </th>
|
<th mat-header-cell *matHeaderCellDef mat-sort-header> Disabled </th>
|
||||||
<td mat-cell *matCellDef="let glAccount">
|
<td mat-cell *matCellDef="let glAccount">
|
||||||
<div [className]="glAccount.disabled === true ? 'disabled' : 'enabled'">
|
<div [className]="glAccount.disabled === true ? 'disabled' : 'enabled'">
|
||||||
<mat-icon matTooltip="{{ glAccount.disabled === true ? 'Disabled' : 'Enabled' }}" matTooltipPosition="right">lens</mat-icon>
|
<fa-icon matTooltip="{{ glAccount.disabled === true ? 'Disabled' : 'Enabled' }}" matTooltipPosition="right" icon="circle" size="lg"></fa-icon>
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
@@ -54,8 +56,8 @@
|
|||||||
<ng-container matColumnDef="manualEntriesAllowed">
|
<ng-container matColumnDef="manualEntriesAllowed">
|
||||||
<th mat-header-cell *matHeaderCellDef mat-sort-header> Manual Entries Allowed </th>
|
<th mat-header-cell *matHeaderCellDef mat-sort-header> Manual Entries Allowed </th>
|
||||||
<td mat-cell *matCellDef="let glAccount">
|
<td mat-cell *matCellDef="let glAccount">
|
||||||
<mat-icon *ngIf="glAccount.manualEntriesAllowed" class="manual-entries-allowed" matTooltip="Allowed" matTooltipPosition="right">check_circle</mat-icon>
|
<fa-icon *ngIf="glAccount.manualEntriesAllowed" class="manual-entries-allowed" matTooltip="Allowed" matTooltipPosition="right" icon="check-circle" size="lg"></fa-icon>
|
||||||
<mat-icon *ngIf="!glAccount.manualEntriesAllowed" class="manual-entries-not-allowed" matTooltip="Not Allowed" matTooltipPosition="right">cancel</mat-icon>
|
<fa-icon *ngIf="!glAccount.manualEntriesAllowed" class="manual-entries-not-allowed" matTooltip="Not Allowed" matTooltipPosition="right" icon="times-circle" size="lg"></fa-icon>
|
||||||
</td>
|
</td>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
|
|
||||||
@@ -65,7 +67,7 @@
|
|||||||
</ng-container>
|
</ng-container>
|
||||||
|
|
||||||
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
|
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
|
||||||
<tr mat-row *matRowDef="let row; columns: displayedColumns;" [routerLink]="['/accounting/chart-of-accounts/gl-accounts/view', row.id]"></tr>
|
<tr mat-row *matRowDef="let row; columns: displayedColumns;" [routerLink]="['gl-accounts/view', row.id]" class="select-row"></tr>
|
||||||
|
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
@@ -78,7 +80,7 @@
|
|||||||
|
|
||||||
<!-- Tree View -->
|
<!-- Tree View -->
|
||||||
|
|
||||||
<div class="container" *ngIf="viewGroup.value === 'treeView'">
|
<div class="container" [hidden]="viewGroup.value !== 'treeView'">
|
||||||
|
|
||||||
<div class="m-b-20" fxLayout="row" fxLayoutAlign="end" fxLayoutGap="20px">
|
<div class="m-b-20" fxLayout="row" fxLayoutAlign="end" fxLayoutGap="20px">
|
||||||
<button mat-raised-button (click)="nestedTreeControl.expandAll()"> <!-- Bug(angular-material): https://github.com/angular/material2/issues/12170 -->
|
<button mat-raised-button (click)="nestedTreeControl.expandAll()"> <!-- Bug(angular-material): https://github.com/angular/material2/issues/12170 -->
|
||||||
@@ -173,9 +175,7 @@
|
|||||||
<li>
|
<li>
|
||||||
<div class="mat-tree-node">
|
<div class="mat-tree-node">
|
||||||
<button mat-icon-button matTreeNodeToggle [attr.aria-label]="'toggle ' + node.name">
|
<button mat-icon-button matTreeNodeToggle [attr.aria-label]="'toggle ' + node.name">
|
||||||
<mat-icon class="mat-icon-rtl-mirror">
|
<fa-icon class="mat-icon-rtl-mirror" icon="{{ nestedTreeControl.isExpanded(node) ? 'chevron-down' : 'chevron-right' }}"></fa-icon>
|
||||||
{{ nestedTreeControl.isExpanded(node) ? 'expand_more' : 'chevron_right' }}
|
|
||||||
</mat-icon>
|
|
||||||
</button>
|
</button>
|
||||||
<span (click)="viewGLAccountNode(node)">
|
<span (click)="viewGLAccountNode(node)">
|
||||||
<span *ngIf="node.glCode">{{ '(' + node.glCode + ')' }}</span>
|
<span *ngIf="node.glCode">{{ '(' + node.glCode + ')' }}</span>
|
||||||
|
|||||||
@@ -1,49 +1,54 @@
|
|||||||
table {
|
table {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
|
||||||
|
|
||||||
.gl-account-tree-invisible {
|
.select-row:hover {
|
||||||
display: none;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
.gl-account-tree ul,
|
|
||||||
.gl-account-tree li {
|
|
||||||
margin-top: 0;
|
|
||||||
margin-bottom: 0;
|
|
||||||
list-style-type: none;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.gl-account-tree {
|
.gl-account-tree {
|
||||||
|
ul,
|
||||||
|
li {
|
||||||
|
margin-top: 0;
|
||||||
|
margin-bottom: 0;
|
||||||
|
list-style-type: none;
|
||||||
|
}
|
||||||
|
|
||||||
li {
|
li {
|
||||||
span {
|
span {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.gl-account-tree-invisible {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.content {
|
.content {
|
||||||
div {
|
div {
|
||||||
margin: 1rem 0;
|
margin: 1rem 0;
|
||||||
word-wrap: break-word;
|
word-wrap: break-word;
|
||||||
}
|
|
||||||
|
|
||||||
.header {
|
&.header {
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: CONFIGURE THESE CLASSES GLOBALLY
|
||||||
|
.enabled {
|
||||||
|
color: #32cd32;
|
||||||
|
}
|
||||||
|
|
||||||
.disabled {
|
.disabled {
|
||||||
color: red;
|
color: #f44366;
|
||||||
}
|
|
||||||
|
|
||||||
.enabled {
|
|
||||||
color: green;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.manual-entries-allowed {
|
.manual-entries-allowed {
|
||||||
color: green;
|
color: #32cd32;
|
||||||
}
|
}
|
||||||
|
|
||||||
.manual-entries-not-allowed {
|
.manual-entries-not-allowed {
|
||||||
color: red;
|
color: #f44366;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,14 +1,22 @@
|
|||||||
|
/** Angular Imports */
|
||||||
import { Component, ViewChild, OnInit, AfterViewInit } from '@angular/core';
|
import { Component, ViewChild, OnInit, AfterViewInit } from '@angular/core';
|
||||||
import { MatPaginator, MatSort, MatTableDataSource, MatTreeNestedDataSource } from '@angular/material';
|
import { MatPaginator, MatSort, MatTableDataSource, MatTreeNestedDataSource } from '@angular/material';
|
||||||
import { NestedTreeControl } from '@angular/cdk/tree';
|
import { NestedTreeControl } from '@angular/cdk/tree';
|
||||||
import { FormControl } from '@angular/forms';
|
import { FormControl } from '@angular/forms';
|
||||||
import { ActivatedRoute } from '@angular/router';
|
import { ActivatedRoute } from '@angular/router';
|
||||||
|
|
||||||
|
/** rxjs Imports */
|
||||||
import { of } from 'rxjs';
|
import { of } from 'rxjs';
|
||||||
|
|
||||||
|
/** Custom Models */
|
||||||
import { GLAccountNode } from './gl-account-node.model';
|
import { GLAccountNode } from './gl-account-node.model';
|
||||||
|
|
||||||
|
/** Custom Services */
|
||||||
import { GlAccountTreeService } from './gl-account-tree.service';
|
import { GlAccountTreeService } from './gl-account-tree.service';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Chart of accounts component.
|
||||||
|
*/
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'mifosx-chart-of-accounts',
|
selector: 'mifosx-chart-of-accounts',
|
||||||
templateUrl: './chart-of-accounts.component.html',
|
templateUrl: './chart-of-accounts.component.html',
|
||||||
@@ -16,37 +24,55 @@ import { GlAccountTreeService } from './gl-account-tree.service';
|
|||||||
})
|
})
|
||||||
export class ChartOfAccountsComponent implements AfterViewInit, OnInit {
|
export class ChartOfAccountsComponent implements AfterViewInit, OnInit {
|
||||||
|
|
||||||
|
/** Button toggle group form control for type of view. (list/tree) */
|
||||||
viewGroup = new FormControl('listView');
|
viewGroup = new FormControl('listView');
|
||||||
|
/** GL Account data. */
|
||||||
glAccountData: any;
|
glAccountData: any;
|
||||||
|
/** Columns to be displayed in chart of accounts table. */
|
||||||
displayedColumns: string[] = ['name', 'glCode', 'glAccountType', 'disabled', 'manualEntriesAllowed', 'usedAs'];
|
displayedColumns: string[] = ['name', 'glCode', 'glAccountType', 'disabled', 'manualEntriesAllowed', 'usedAs'];
|
||||||
tableDataSource: any;
|
/** Data source for chart of accounts table. */
|
||||||
|
tableDataSource: MatTableDataSource<any>;
|
||||||
@ViewChild(MatPaginator) paginator: MatPaginator;
|
/** Nested tree control for chart of accounts tree. */
|
||||||
@ViewChild(MatSort) sort: MatSort;
|
|
||||||
|
|
||||||
nestedTreeControl: NestedTreeControl<GLAccountNode>;
|
nestedTreeControl: NestedTreeControl<GLAccountNode>;
|
||||||
|
/** Nested tree data source for chart of accounts tree. */
|
||||||
nestedTreeDataSource: MatTreeNestedDataSource<GLAccountNode>;
|
nestedTreeDataSource: MatTreeNestedDataSource<GLAccountNode>;
|
||||||
|
/** Selected GL Account. */
|
||||||
glAccount: GLAccountNode;
|
glAccount: GLAccountNode;
|
||||||
|
|
||||||
|
/** Paginator for chart of accounts table. */
|
||||||
|
@ViewChild(MatPaginator) paginator: MatPaginator;
|
||||||
|
/** Sorter for chart of accounts table. */
|
||||||
|
@ViewChild(MatSort) sort: MatSort;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the gl accounts data from `resolve` and initializes(generates) gl accounts tree.
|
||||||
|
* @param {GlAccountTreeService} glAccountTreeService GL Account tree service.
|
||||||
|
* @param {ActivatedRoute} route Activated Route.
|
||||||
|
*/
|
||||||
constructor(private glAccountTreeService: GlAccountTreeService,
|
constructor(private glAccountTreeService: GlAccountTreeService,
|
||||||
private route: ActivatedRoute) {
|
private route: ActivatedRoute) {
|
||||||
this.route.data.subscribe((data: { glAccountData: any }) => {
|
this.route.data.subscribe((data: { chartOfAccounts: any }) => {
|
||||||
this.glAccountData = data.glAccountData;
|
this.glAccountData = data.chartOfAccounts;
|
||||||
glAccountTreeService.initialize(this.glAccountData);
|
glAccountTreeService.initialize(this.glAccountData);
|
||||||
});
|
});
|
||||||
this.nestedTreeControl = new NestedTreeControl<GLAccountNode>(this._getChildren);
|
this.nestedTreeControl = new NestedTreeControl<GLAccountNode>(this._getChildren);
|
||||||
this.nestedTreeDataSource = new MatTreeNestedDataSource();
|
this.nestedTreeDataSource = new MatTreeNestedDataSource<GLAccountNode>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes the data source for chart of accounts table and tree.
|
||||||
|
*/
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
this.tableDataSource = new MatTableDataSource(this.glAccountData);
|
this.tableDataSource = new MatTableDataSource(this.glAccountData);
|
||||||
this.glAccountTreeService.treeDataChange.subscribe((glAccountTreeData: any) => {
|
this.glAccountTreeService.treeDataChange.subscribe((glAccountTreeData: GLAccountNode[]) => {
|
||||||
this.nestedTreeDataSource.data = glAccountTreeData;
|
this.nestedTreeDataSource.data = glAccountTreeData;
|
||||||
this.nestedTreeControl.expand(this.nestedTreeDataSource.data[0]);
|
this.nestedTreeControl.expand(this.nestedTreeDataSource.data[0]);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes the paginator and sorter for chart of accounts table.
|
||||||
|
*/
|
||||||
ngAfterViewInit() {
|
ngAfterViewInit() {
|
||||||
this.tableDataSource.paginator = this.paginator;
|
this.tableDataSource.paginator = this.paginator;
|
||||||
this.tableDataSource.sortingDataAccessor = (glAccount: any, property: any) => {
|
this.tableDataSource.sortingDataAccessor = (glAccount: any, property: any) => {
|
||||||
@@ -59,12 +85,18 @@ export class ChartOfAccountsComponent implements AfterViewInit, OnInit {
|
|||||||
this.tableDataSource.sort = this.sort;
|
this.tableDataSource.sort = this.sort;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Filters data in chart of accounts table based on passed value.
|
||||||
|
* @param {string} filterValue Value to filter data.
|
||||||
|
*/
|
||||||
applyFilter(filterValue: string) {
|
applyFilter(filterValue: string) {
|
||||||
this.tableDataSource.filter = filterValue.trim().toLowerCase();
|
this.tableDataSource.filter = filterValue.trim().toLowerCase();
|
||||||
}
|
}
|
||||||
|
|
||||||
hasNestedChild = (_: number, node: GLAccountNode) => node.children.length;
|
/**
|
||||||
|
* View selected gl account.
|
||||||
|
* @param {GLAccountNode} glAccount GL Account to be viewed.
|
||||||
|
*/
|
||||||
viewGLAccountNode(glAccount: GLAccountNode) {
|
viewGLAccountNode(glAccount: GLAccountNode) {
|
||||||
if (glAccount.glCode) {
|
if (glAccount.glCode) {
|
||||||
this.glAccount = glAccount;
|
this.glAccount = glAccount;
|
||||||
@@ -73,6 +105,14 @@ export class ChartOfAccountsComponent implements AfterViewInit, OnInit {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if selected node in tree has children.
|
||||||
|
*/
|
||||||
|
hasNestedChild = (_: number, node: GLAccountNode) => node.children.length;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the children of selected node in tree.
|
||||||
|
*/
|
||||||
private _getChildren = (node: GLAccountNode) => of(node.children);
|
private _getChildren = (node: GLAccountNode) => of(node.children);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,14 +1,28 @@
|
|||||||
|
/** Angular Imports */
|
||||||
import { Injectable } from '@angular/core';
|
import { Injectable } from '@angular/core';
|
||||||
import { Resolve } from '@angular/router';
|
import { Resolve } from '@angular/router';
|
||||||
|
|
||||||
|
/** rxjs Imports */
|
||||||
import { Observable } from 'rxjs';
|
import { Observable } from 'rxjs';
|
||||||
|
|
||||||
|
/** Custom Services */
|
||||||
import { AccountingService } from '../accounting.service';
|
import { AccountingService } from '../accounting.service';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Chart of acocunts data resolver.
|
||||||
|
*/
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class ChartOfAccountsResolver implements Resolve<Object> {
|
export class ChartOfAccountsResolver implements Resolve<Object> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {AccountingService} accountingService Accounting service.
|
||||||
|
*/
|
||||||
constructor(private accountingService: AccountingService) {}
|
constructor(private accountingService: AccountingService) {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the chart of accounts data.
|
||||||
|
* @returns {Observable<any>}
|
||||||
|
*/
|
||||||
resolve(): Observable<any> {
|
resolve(): Observable<any> {
|
||||||
return this.accountingService.getChartOfAccounts();
|
return this.accountingService.getChartOfAccounts();
|
||||||
}
|
}
|
||||||
|
|||||||
+30
@@ -0,0 +1,30 @@
|
|||||||
|
/** Angular Imports */
|
||||||
|
import { Injectable } from '@angular/core';
|
||||||
|
import { Resolve } from '@angular/router';
|
||||||
|
|
||||||
|
/** rxjs Imports */
|
||||||
|
import { Observable } from 'rxjs';
|
||||||
|
|
||||||
|
/** Custom Services */
|
||||||
|
import { AccountingService } from '../../accounting.service';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Chart of accounts template data resolver.
|
||||||
|
*/
|
||||||
|
@Injectable()
|
||||||
|
export class ChartOfAccountsTemplateResolver implements Resolve<Object> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {AccountingService} accountingService Accounting service.
|
||||||
|
*/
|
||||||
|
constructor(private accountingService: AccountingService) {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the chart of accounts template data.
|
||||||
|
* @returns {Observable<any>}
|
||||||
|
*/
|
||||||
|
resolve(): Observable<any> {
|
||||||
|
return this.accountingService.getChartOfAccountsTemplate();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+29
-10
@@ -9,31 +9,48 @@
|
|||||||
<div fxLayout="row wrap" fxLayoutGap="2%" fxLayout.lt-md="column">
|
<div fxLayout="row wrap" fxLayoutGap="2%" fxLayout.lt-md="column">
|
||||||
|
|
||||||
<mat-form-field fxFlex="48%">
|
<mat-form-field fxFlex="48%">
|
||||||
<mat-select placeholder="Account Type" required formControlName="type">
|
<mat-label>Account Type</mat-label>
|
||||||
|
<mat-select required formControlName="type">
|
||||||
<mat-option *ngFor="let accountType of accountTypeData" [value]="accountType.id">
|
<mat-option *ngFor="let accountType of accountTypeData" [value]="accountType.id">
|
||||||
{{ accountType.value }}
|
{{ accountType.value }}
|
||||||
</mat-option>
|
</mat-option>
|
||||||
</mat-select>
|
</mat-select>
|
||||||
|
<mat-error *ngIf="glAccountForm.controls.type.hasError('required')">
|
||||||
|
Account Type is <strong>required</strong>
|
||||||
|
</mat-error>
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
|
|
||||||
<mat-form-field fxFlex="48%">
|
<mat-form-field fxFlex="48%">
|
||||||
<input matInput placeholder="Account Name" required formControlName="name">
|
<mat-label>Account Name</mat-label>
|
||||||
|
<input matInput required formControlName="name">
|
||||||
|
<mat-error *ngIf="glAccountForm.controls.name.hasError('required')">
|
||||||
|
Account Name is <strong>required</strong>
|
||||||
|
</mat-error>
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
|
|
||||||
<mat-form-field fxFlex="48%">
|
<mat-form-field fxFlex="48%">
|
||||||
<mat-select placeholder="Account Usage" required formControlName="usage">
|
<mat-label>Account Usage</mat-label>
|
||||||
|
<mat-select required formControlName="usage">
|
||||||
<mat-option *ngFor="let accountUsage of accountUsageData" [value]="accountUsage.id">
|
<mat-option *ngFor="let accountUsage of accountUsageData" [value]="accountUsage.id">
|
||||||
{{ accountUsage.value }}
|
{{ accountUsage.value }}
|
||||||
</mat-option>
|
</mat-option>
|
||||||
</mat-select>
|
</mat-select>
|
||||||
|
<mat-error *ngIf="glAccountForm.controls.usage.hasError('required')">
|
||||||
|
Account Usage is <strong>required</strong>
|
||||||
|
</mat-error>
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
|
|
||||||
<mat-form-field fxFlex="48%">
|
<mat-form-field fxFlex="48%">
|
||||||
<input matInput placeholder="GL Code" required formControlName="glCode">
|
<mat-label>GL Code</mat-label>
|
||||||
|
<input matInput required formControlName="glCode">
|
||||||
|
<mat-error *ngIf="glAccountForm.controls.glCode.hasError('required')">
|
||||||
|
GL Code is <strong>required</strong>
|
||||||
|
</mat-error>
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
|
|
||||||
<mat-form-field fxFlex="48%">
|
<mat-form-field fxFlex="48%">
|
||||||
<mat-select placeholder="Parent" formControlName="parentId">
|
<mat-label>Parent</mat-label>
|
||||||
|
<mat-select formControlName="parentId">
|
||||||
<mat-option *ngFor="let parent of parentData" [value]="parent.id">
|
<mat-option *ngFor="let parent of parentData" [value]="parent.id">
|
||||||
{{ parent.name }}
|
{{ parent.name }}
|
||||||
</mat-option>
|
</mat-option>
|
||||||
@@ -41,21 +58,23 @@
|
|||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
|
|
||||||
<mat-form-field fxFlex="28%">
|
<mat-form-field fxFlex="28%">
|
||||||
<mat-select placeholder="Tag" formControlName="tagId">
|
<mat-label>Tag</mat-label>
|
||||||
|
<mat-select formControlName="tagId">
|
||||||
<mat-option *ngFor="let tag of tagData" [value]="tag.id">
|
<mat-option *ngFor="let tag of tagData" [value]="tag.id">
|
||||||
{{ tag.name }}
|
{{ tag.name }}
|
||||||
</mat-option>
|
</mat-option>
|
||||||
</mat-select>
|
</mat-select>
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
|
|
||||||
<div fxFlex="18%" class="manualEntriesAllowedWrapper">
|
<div fxFlex="18%" class="manual-entries-allowed-wrapper">
|
||||||
<mat-checkbox labelPosition="before" required formControlName="manualEntriesAllowed" class="manualEntriesAllowed">
|
<mat-checkbox labelPosition="before" required formControlName="manualEntriesAllowed" class="manual-entries-allowed">
|
||||||
Manual Entries Allowed
|
Manual Entries Allowed
|
||||||
</mat-checkbox>
|
</mat-checkbox>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<mat-form-field fxFlex="98%">
|
<mat-form-field fxFlex="98%">
|
||||||
<textarea matInput placeholder="Description" formControlName="description"></textarea>
|
<mat-label>Description</mat-label>
|
||||||
|
<textarea matInput formControlName="description"></textarea>
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
@@ -64,7 +83,7 @@
|
|||||||
|
|
||||||
<mat-card-actions fxLayout="row" fxLayout.xs="column" fxLayoutAlign="center" fxLayoutGap="5px">
|
<mat-card-actions fxLayout="row" fxLayout.xs="column" fxLayoutAlign="center" fxLayoutGap="5px">
|
||||||
<button type="button" mat-raised-button [routerLink]="[cancelRoute]">Cancel</button>
|
<button type="button" mat-raised-button [routerLink]="[cancelRoute]">Cancel</button>
|
||||||
<button mat-raised-button color="primary">Submit</button>
|
<button mat-raised-button color="primary" [disabled]="!glAccountForm.valid">Submit</button>
|
||||||
</mat-card-actions>
|
</mat-card-actions>
|
||||||
|
|
||||||
</form>
|
</form>
|
||||||
|
|||||||
+2
-2
@@ -1,7 +1,7 @@
|
|||||||
.manualEntriesAllowedWrapper {
|
.manual-entries-allowed-wrapper {
|
||||||
position: relative;
|
position: relative;
|
||||||
|
|
||||||
.manualEntriesAllowed {
|
.manual-entries-allowed {
|
||||||
padding: 0 0 17.5px 0;
|
padding: 0 0 17.5px 0;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
|
|||||||
+47
-17
@@ -1,9 +1,14 @@
|
|||||||
|
/** Angular Imports */
|
||||||
import { Component, OnInit } from '@angular/core';
|
import { Component, OnInit } from '@angular/core';
|
||||||
import { FormGroup, FormBuilder, Validators } from '@angular/forms';
|
import { FormGroup, FormBuilder, Validators } from '@angular/forms';
|
||||||
import { Router, ActivatedRoute } from '@angular/router';
|
import { Router, ActivatedRoute } from '@angular/router';
|
||||||
|
|
||||||
|
/** Custom Services */
|
||||||
import { AccountingService } from '../../accounting.service';
|
import { AccountingService } from '../../accounting.service';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create gl account component.
|
||||||
|
*/
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'mifosx-create-gl-account',
|
selector: 'mifosx-create-gl-account',
|
||||||
templateUrl: './create-gl-account.component.html',
|
templateUrl: './create-gl-account.component.html',
|
||||||
@@ -11,18 +16,32 @@ import { AccountingService } from '../../accounting.service';
|
|||||||
})
|
})
|
||||||
export class CreateGlAccountComponent implements OnInit {
|
export class CreateGlAccountComponent implements OnInit {
|
||||||
|
|
||||||
|
/** GL account form. */
|
||||||
glAccountForm: FormGroup;
|
glAccountForm: FormGroup;
|
||||||
|
/** Chart of accounts data. */
|
||||||
chartOfAccountsData: any;
|
chartOfAccountsData: any;
|
||||||
|
/** Account type data. */
|
||||||
accountTypeData: any;
|
accountTypeData: any;
|
||||||
parentData: any;
|
/** Account usage data. */
|
||||||
accountUsageData: any;
|
accountUsageData: any;
|
||||||
|
/** Parent data. */
|
||||||
|
parentData: any;
|
||||||
|
/** Tag data. */
|
||||||
tagData: any;
|
tagData: any;
|
||||||
|
/** Account type id. (for creation of sub-ledger account) */
|
||||||
accountTypeId: number;
|
accountTypeId: number;
|
||||||
|
/** Parent id. (for creation of sub-ledger account) */
|
||||||
parentId: number;
|
parentId: number;
|
||||||
|
/** Cancel route. (depending on creation of gl account or sub-ledger account) */
|
||||||
|
cancelRoute = '../../';
|
||||||
|
|
||||||
cancelRoute = '/accounting/chart-of-accounts';
|
/**
|
||||||
|
* Retrieves the chart of accounts data from `resolve`.
|
||||||
|
* @param {FormBuilder} formBuilder Form Builder.
|
||||||
|
* @param {AccountingService} accountingService Accounting Service.
|
||||||
|
* @param {ActivatedRoute} route Activated Route.
|
||||||
|
* @param {Router} router Router for navigation.
|
||||||
|
*/
|
||||||
constructor(private formBuilder: FormBuilder,
|
constructor(private formBuilder: FormBuilder,
|
||||||
private accountingService: AccountingService,
|
private accountingService: AccountingService,
|
||||||
private route: ActivatedRoute,
|
private route: ActivatedRoute,
|
||||||
@@ -31,39 +50,44 @@ export class CreateGlAccountComponent implements OnInit {
|
|||||||
this.accountTypeId = Number(params.get('accountType'));
|
this.accountTypeId = Number(params.get('accountType'));
|
||||||
this.parentId = Number(params.get('parent'));
|
this.parentId = Number(params.get('parent'));
|
||||||
if (this.parentId) {
|
if (this.parentId) {
|
||||||
this.cancelRoute = `/accounting/chart-of-accounts/gl-accounts/view/${this.parentId}`;
|
this.cancelRoute = `../view/${this.parentId}`;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
this.route.data.subscribe((data: { chartOfAccountsTemplate: any }) => {
|
||||||
|
this.chartOfAccountsData = data.chartOfAccountsTemplate;
|
||||||
|
this.accountTypeData = data.chartOfAccountsTemplate.accountTypeOptions;
|
||||||
|
this.accountUsageData = data.chartOfAccountsTemplate.usageOptions;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates and sets gl account form.
|
||||||
|
*/
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
this.createGlAccountForm();
|
this.createGlAccountForm();
|
||||||
this.getChartOfAccountsTemplate();
|
|
||||||
this.setGLAccountForm();
|
this.setGLAccountForm();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates gl account form.
|
||||||
|
*/
|
||||||
createGlAccountForm() {
|
createGlAccountForm() {
|
||||||
this.glAccountForm = this.formBuilder.group({
|
this.glAccountForm = this.formBuilder.group({
|
||||||
'type': ['', Validators.required],
|
'type': ['', Validators.required],
|
||||||
'name': ['', Validators.required],
|
'name': ['', Validators.required],
|
||||||
'usage': ['', Validators.required],
|
'usage': ['', Validators.required],
|
||||||
'glCode': ['', Validators.required],
|
'glCode': ['', Validators.required],
|
||||||
'parentId': [this.parentId],
|
'parentId': [this.parentId || undefined],
|
||||||
'tagId': [''],
|
'tagId': [''],
|
||||||
'manualEntriesAllowed': [true, Validators.required],
|
'manualEntriesAllowed': [true, Validators.required],
|
||||||
'description': ['']
|
'description': ['']
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
getChartOfAccountsTemplate() {
|
/**
|
||||||
this.accountingService.getChartOfAccountsTemplate().subscribe((chartOfAccountsData: any) => {
|
* Sets gl account form for selected account type.
|
||||||
this.chartOfAccountsData = chartOfAccountsData;
|
*/
|
||||||
this.accountTypeData = chartOfAccountsData.accountTypeOptions;
|
|
||||||
this.accountUsageData = chartOfAccountsData.usageOptions;
|
|
||||||
this.glAccountForm.get('type').setValue(this.accountTypeId);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
setGLAccountForm() {
|
setGLAccountForm() {
|
||||||
this.glAccountForm.get('type').valueChanges.subscribe(accountTypeId => {
|
this.glAccountForm.get('type').valueChanges.subscribe(accountTypeId => {
|
||||||
switch (accountTypeId) {
|
switch (accountTypeId) {
|
||||||
@@ -84,11 +108,17 @@ export class CreateGlAccountComponent implements OnInit {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
this.glAccountForm.get('type').setValue(this.accountTypeId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Submits the gl account form and creates gl account,
|
||||||
|
* if successful redirects to view created account.
|
||||||
|
*/
|
||||||
submit() {
|
submit() {
|
||||||
this.accountingService.createGlAccount(this.glAccountForm.value).subscribe((response: any) => {
|
this.accountingService.createGlAccount(this.glAccountForm.value).subscribe((response: any) => {
|
||||||
this.router.navigate(['/accounting/chart-of-accounts/gl-accounts/view', response.resourceId]);
|
this.router.navigate(['../view', response.resourceId], { relativeTo: this.route });
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+30
-11
@@ -9,31 +9,48 @@
|
|||||||
<div fxLayout="row wrap" fxLayoutGap="2%" fxLayout.lt-md="column">
|
<div fxLayout="row wrap" fxLayoutGap="2%" fxLayout.lt-md="column">
|
||||||
|
|
||||||
<mat-form-field fxFlex="48%">
|
<mat-form-field fxFlex="48%">
|
||||||
<mat-select placeholder="Account Type" required formControlName="type">
|
<mat-label>Account Type</mat-label>
|
||||||
|
<mat-select required formControlName="type">
|
||||||
<mat-option *ngFor="let accountType of accountTypeData" [value]="accountType.id">
|
<mat-option *ngFor="let accountType of accountTypeData" [value]="accountType.id">
|
||||||
{{ accountType.value }}
|
{{ accountType.value }}
|
||||||
</mat-option>
|
</mat-option>
|
||||||
</mat-select>
|
</mat-select>
|
||||||
|
<mat-error *ngIf="glAccountForm.controls.type.hasError('required')">
|
||||||
|
Account Type is <strong>required</strong>
|
||||||
|
</mat-error>
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
|
|
||||||
<mat-form-field fxFlex="48%">
|
<mat-form-field fxFlex="48%">
|
||||||
<input matInput placeholder="Account Name" required formControlName="name">
|
<mat-label>Account Name</mat-label>
|
||||||
|
<input matInput required formControlName="name">
|
||||||
|
<mat-error *ngIf="glAccountForm.controls.name.hasError('required')">
|
||||||
|
Account Name is <strong>required</strong>
|
||||||
|
</mat-error>
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
|
|
||||||
<mat-form-field fxFlex="48%">
|
<mat-form-field fxFlex="48%">
|
||||||
<mat-select placeholder="Account Usage" required formControlName="usage">
|
<mat-label>Account Usage</mat-label>
|
||||||
|
<mat-select required formControlName="usage">
|
||||||
<mat-option *ngFor="let accountUsage of accountUsageData" [value]="accountUsage.id">
|
<mat-option *ngFor="let accountUsage of accountUsageData" [value]="accountUsage.id">
|
||||||
{{ accountUsage.value }}
|
{{ accountUsage.value }}
|
||||||
</mat-option>
|
</mat-option>
|
||||||
</mat-select>
|
</mat-select>
|
||||||
|
<mat-error *ngIf="glAccountForm.controls.usage.hasError('required')">
|
||||||
|
Account Usage is <strong>required</strong>
|
||||||
|
</mat-error>
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
|
|
||||||
<mat-form-field fxFlex="48%">
|
<mat-form-field fxFlex="48%">
|
||||||
<input matInput placeholder="GL Code" required formControlName="glCode">
|
<mat-label>GL Code</mat-label>
|
||||||
|
<input matInput required formControlName="glCode">
|
||||||
|
<mat-error *ngIf="glAccountForm.controls.glCode.hasError('required')">
|
||||||
|
GL Code is <strong>required</strong>
|
||||||
|
</mat-error>
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
|
|
||||||
<mat-form-field fxFlex="48%">
|
<mat-form-field fxFlex="48%">
|
||||||
<mat-select placeholder="Parent" formControlName="parentId">
|
<mat-label>Parent</mat-label>
|
||||||
|
<mat-select formControlName="parentId">
|
||||||
<mat-option *ngFor="let parent of parentData" [value]="parent.id">
|
<mat-option *ngFor="let parent of parentData" [value]="parent.id">
|
||||||
{{ parent.name }}
|
{{ parent.name }}
|
||||||
</mat-option>
|
</mat-option>
|
||||||
@@ -41,21 +58,23 @@
|
|||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
|
|
||||||
<mat-form-field fxFlex="28%">
|
<mat-form-field fxFlex="28%">
|
||||||
<mat-select placeholder="Tag" formControlName="tagId">
|
<mat-label>Tag</mat-label>
|
||||||
|
<mat-select formControlName="tagId">
|
||||||
<mat-option *ngFor="let tag of tagData" [value]="tag.id">
|
<mat-option *ngFor="let tag of tagData" [value]="tag.id">
|
||||||
{{ tag.name }}
|
{{ tag.name }}
|
||||||
</mat-option>
|
</mat-option>
|
||||||
</mat-select>
|
</mat-select>
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
|
|
||||||
<div fxFlex="18%" class="manualEntriesAllowedWrapper">
|
<div fxFlex="18%" class="manual-entries-allowed-wrapper">
|
||||||
<mat-checkbox labelPosition="before" required formControlName="manualEntriesAllowed" class="manualEntriesAllowed">
|
<mat-checkbox labelPosition="before" required formControlName="manualEntriesAllowed" class="manual-entries-allowed">
|
||||||
Manual Entries Allowed
|
Manual Entries Allowed
|
||||||
</mat-checkbox>
|
</mat-checkbox>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<mat-form-field fxFlex="98%">
|
<mat-form-field fxFlex="98%">
|
||||||
<textarea matInput placeholder="Description" formControlName="description"></textarea>
|
<mat-label>Description</mat-label>
|
||||||
|
<textarea matInput formControlName="description"></textarea>
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
@@ -63,8 +82,8 @@
|
|||||||
</mat-card-content>
|
</mat-card-content>
|
||||||
|
|
||||||
<mat-card-actions fxLayout="row" fxLayout.xs="column" fxLayoutAlign="center" fxLayoutGap="5px">
|
<mat-card-actions fxLayout="row" fxLayout.xs="column" fxLayoutAlign="center" fxLayoutGap="5px">
|
||||||
<button type="button" mat-raised-button [routerLink]="['/accounting/chart-of-accounts']">Cancel</button>
|
<button type="button" mat-raised-button [routerLink]="['../']">Cancel</button>
|
||||||
<button mat-raised-button color="primary">Submit</button>
|
<button mat-raised-button color="primary" [disabled]="glAccountForm.pristine">Submit</button>
|
||||||
</mat-card-actions>
|
</mat-card-actions>
|
||||||
|
|
||||||
</form>
|
</form>
|
||||||
|
|||||||
@@ -0,0 +1,10 @@
|
|||||||
|
.manual-entries-allowed-wrapper {
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
.manual-entries-allowed {
|
||||||
|
padding: 0 0 17.5px 0;
|
||||||
|
position: absolute;
|
||||||
|
bottom: 0;
|
||||||
|
right: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,9 +1,14 @@
|
|||||||
|
/** Angular Imports */
|
||||||
import { Component, OnInit } from '@angular/core';
|
import { Component, OnInit } from '@angular/core';
|
||||||
import { ActivatedRoute, Router } from '@angular/router';
|
import { ActivatedRoute, Router } from '@angular/router';
|
||||||
import { FormGroup, FormBuilder, Validators } from '@angular/forms';
|
import { FormGroup, FormBuilder, Validators } from '@angular/forms';
|
||||||
|
|
||||||
|
/** Custom Services */
|
||||||
import { AccountingService } from '../../accounting.service';
|
import { AccountingService } from '../../accounting.service';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Edit gl account component.
|
||||||
|
*/
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'mifosx-edit-gl-account',
|
selector: 'mifosx-edit-gl-account',
|
||||||
templateUrl: './edit-gl-account.component.html',
|
templateUrl: './edit-gl-account.component.html',
|
||||||
@@ -11,27 +16,46 @@ import { AccountingService } from '../../accounting.service';
|
|||||||
})
|
})
|
||||||
export class EditGlAccountComponent implements OnInit {
|
export class EditGlAccountComponent implements OnInit {
|
||||||
|
|
||||||
|
/** GL account form. */
|
||||||
glAccountForm: FormGroup;
|
glAccountForm: FormGroup;
|
||||||
|
/** GL account and chart of accounts data. */
|
||||||
glAccount: any;
|
glAccount: any;
|
||||||
|
/** Account type data. */
|
||||||
accountTypeData: any;
|
accountTypeData: any;
|
||||||
|
/** Account usage data. */
|
||||||
accountUsageData: any;
|
accountUsageData: any;
|
||||||
|
/** Parent data. */
|
||||||
parentData: any;
|
parentData: any;
|
||||||
|
/** Tag data. */
|
||||||
tagData: any;
|
tagData: any;
|
||||||
|
|
||||||
constructor(private route: ActivatedRoute,
|
/**
|
||||||
private formBuilder: FormBuilder,
|
* Retrieves the chart of accounts data from `resolve`.
|
||||||
|
* @param {FormBuilder} formBuilder Form Builder.
|
||||||
|
* @param {AccountingService} accountingService Accounting Service.
|
||||||
|
* @param {ActivatedRoute} route Activated Route.
|
||||||
|
* @param {Router} router Router for navigation.
|
||||||
|
*/
|
||||||
|
constructor(private formBuilder: FormBuilder,
|
||||||
private accountingService: AccountingService,
|
private accountingService: AccountingService,
|
||||||
|
private route: ActivatedRoute,
|
||||||
private router: Router) {
|
private router: Router) {
|
||||||
this.route.data.subscribe((data: { glAccount: any }) => {
|
this.route.data.subscribe((data: { glAccountAndChartOfAccountsTemplate: any }) => {
|
||||||
this.glAccount = data.glAccount;
|
this.glAccount = data.glAccountAndChartOfAccountsTemplate;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates and sets gl account form.
|
||||||
|
*/
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
this.createGlAccountForm();
|
this.createGlAccountForm();
|
||||||
this.setGLAccountForm();
|
this.setGLAccountForm();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates gl account form.
|
||||||
|
*/
|
||||||
createGlAccountForm() {
|
createGlAccountForm() {
|
||||||
this.glAccountForm = this.formBuilder.group({
|
this.glAccountForm = this.formBuilder.group({
|
||||||
'type': ['', Validators.required],
|
'type': ['', Validators.required],
|
||||||
@@ -45,6 +69,9 @@ export class EditGlAccountComponent implements OnInit {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets gl account form for selected account type.
|
||||||
|
*/
|
||||||
setGLAccountForm() {
|
setGLAccountForm() {
|
||||||
this.accountTypeData = this.glAccount.accountTypeOptions;
|
this.accountTypeData = this.glAccount.accountTypeOptions;
|
||||||
this.accountUsageData = this.glAccount.usageOptions;
|
this.accountUsageData = this.glAccount.usageOptions;
|
||||||
@@ -67,13 +94,18 @@ export class EditGlAccountComponent implements OnInit {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
this.glAccountForm.get('type').setValue(this.glAccount.type.id);
|
this.glAccountForm.get('type').setValue(this.glAccount.type.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Submits the gl account form and updates gl account,
|
||||||
|
* if successful redirects to view updated account.
|
||||||
|
*/
|
||||||
submit() {
|
submit() {
|
||||||
this.accountingService.updateGlAccount(this.glAccount.id, this.glAccountForm.value)
|
this.accountingService.updateGlAccount(this.glAccount.id, this.glAccountForm.value)
|
||||||
.subscribe((response: any) => {
|
.subscribe((response: any) => {
|
||||||
this.router.navigate(['/accounting/chart-of-accounts/gl-accounts/view', response.resourceId]);
|
this.router.navigate(['../../', response.resourceId], { relativeTo: this.route });
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+53
@@ -0,0 +1,53 @@
|
|||||||
|
/** Angular Imports */
|
||||||
|
import { Injectable } from '@angular/core';
|
||||||
|
import { Resolve, ActivatedRouteSnapshot } from '@angular/router';
|
||||||
|
|
||||||
|
/** rxjs Imports */
|
||||||
|
import { Observable } from 'rxjs';
|
||||||
|
import { map } from 'rxjs/operators';
|
||||||
|
|
||||||
|
/** Custom Services */
|
||||||
|
import { AccountingService } from '../accounting.service';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* GL Account and chart of accounts template data resolver.
|
||||||
|
*/
|
||||||
|
@Injectable()
|
||||||
|
export class GlAccountAndChartOfAccountsTemplateResolver implements Resolve<Object> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {AccountingService} accountingService Accounting service.
|
||||||
|
*/
|
||||||
|
constructor(private accountingService: AccountingService) {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the gl account and chart of accounts template data.
|
||||||
|
* @returns {Observable<any>}
|
||||||
|
*/
|
||||||
|
resolve(route: ActivatedRouteSnapshot): Observable<any> {
|
||||||
|
const id = route.paramMap.get('id');
|
||||||
|
|
||||||
|
return this.accountingService.getGlAccount(id, true).pipe(
|
||||||
|
map((glAccountData: any) => {
|
||||||
|
let accountOptions = [];
|
||||||
|
switch (glAccountData.type.value) {
|
||||||
|
case 'ASSET': accountOptions = glAccountData.assetHeaderAccountOptions;
|
||||||
|
break;
|
||||||
|
case 'EQUITY': accountOptions = glAccountData.equityHeaderAccountOptions;
|
||||||
|
break;
|
||||||
|
case 'EXPENSE': accountOptions = glAccountData.expenseHeaderAccountOptions;
|
||||||
|
break;
|
||||||
|
case 'INCOME': accountOptions = glAccountData.incomeHeaderAccountOptions;
|
||||||
|
break;
|
||||||
|
case 'LIABILITY': accountOptions = glAccountData.liabilityHeaderAccountOptions;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
glAccountData.parent = accountOptions.find((accountOption: any) => {
|
||||||
|
return accountOption.id === glAccountData.parentId;
|
||||||
|
});
|
||||||
|
return glAccountData;
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,11 +1,18 @@
|
|||||||
|
/**
|
||||||
|
* GL Account Node model.
|
||||||
|
*/
|
||||||
export class GLAccountNode {
|
export class GLAccountNode {
|
||||||
|
|
||||||
|
/** GL Account Node children. */
|
||||||
children: GLAccountNode[];
|
children: GLAccountNode[];
|
||||||
|
|
||||||
name: string;
|
name: string;
|
||||||
glCode: string;
|
glCode: string;
|
||||||
type: string;
|
type: string;
|
||||||
usage: string;
|
usage: string;
|
||||||
manualEntriesAllowed: boolean;
|
manualEntriesAllowed: boolean;
|
||||||
description: string;
|
description: string;
|
||||||
|
|
||||||
constructor(name: string,
|
constructor(name: string,
|
||||||
glCode: string = '',
|
glCode: string = '',
|
||||||
type: string = '',
|
type: string = '',
|
||||||
@@ -20,4 +27,5 @@ export class GLAccountNode {
|
|||||||
this.description = description;
|
this.description = description;
|
||||||
this.children = [];
|
this.children = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,30 +1,50 @@
|
|||||||
|
/** Angular Imports */
|
||||||
import { Injectable } from '@angular/core';
|
import { Injectable } from '@angular/core';
|
||||||
|
|
||||||
|
/** rxjs Imports */
|
||||||
import { BehaviorSubject } from 'rxjs';
|
import { BehaviorSubject } from 'rxjs';
|
||||||
|
|
||||||
|
/** Custom Components */
|
||||||
import { GLAccountNode } from './gl-account-node.model';
|
import { GLAccountNode } from './gl-account-node.model';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* GL Account tree service.
|
||||||
|
*/
|
||||||
@Injectable({
|
@Injectable({
|
||||||
providedIn: 'root'
|
providedIn: 'root'
|
||||||
})
|
})
|
||||||
export class GlAccountTreeService {
|
export class GlAccountTreeService {
|
||||||
|
|
||||||
|
/** GL Account data. */
|
||||||
glAccountData: any;
|
glAccountData: any;
|
||||||
|
/** Chart of accounts tree data behavior subject to represent chart of accounts tree nodes. */
|
||||||
treeDataChange = new BehaviorSubject<GLAccountNode[]>([]);
|
treeDataChange = new BehaviorSubject<GLAccountNode[]>([]);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the chart of accounts tree nodes.
|
||||||
|
*/
|
||||||
get treeData(): GLAccountNode[] { return this.treeDataChange.value; }
|
get treeData(): GLAccountNode[] { return this.treeDataChange.value; }
|
||||||
|
|
||||||
constructor() { }
|
constructor() { }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Builds the chart of accounts tree and emits the value.
|
||||||
|
* @param {any} glAccountData Chart of accounts data.
|
||||||
|
*/
|
||||||
initialize(glAccountData: any) {
|
initialize(glAccountData: any) {
|
||||||
const data = this.buildGLAccountTree(glAccountData);
|
const treeData = this.buildGLAccountTree(glAccountData);
|
||||||
this.treeDataChange.next(data);
|
this.treeDataChange.next(treeData);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Builds and returns the chart of accounts tree.
|
||||||
|
* @param {any} glAccountData Chart of accounts data.
|
||||||
|
* @returns {GLAccountNode[]} Chart of accounts tree nodes.
|
||||||
|
*/
|
||||||
buildGLAccountTree(glAccountData: any): GLAccountNode[] {
|
buildGLAccountTree(glAccountData: any): GLAccountNode[] {
|
||||||
const glAccountTree: GLAccountNode[] = [];
|
const glAccountTree: GLAccountNode[] = [];
|
||||||
|
|
||||||
|
// Header nodes
|
||||||
glAccountTree.push(new GLAccountNode('GL ACCOUNTS'));
|
glAccountTree.push(new GLAccountNode('GL ACCOUNTS'));
|
||||||
glAccountTree[0].children.push(new GLAccountNode('ASSET'));
|
glAccountTree[0].children.push(new GLAccountNode('ASSET'));
|
||||||
glAccountTree[0].children.push(new GLAccountNode('EQUITY'));
|
glAccountTree[0].children.push(new GLAccountNode('EQUITY'));
|
||||||
@@ -32,6 +52,7 @@ export class GlAccountTreeService {
|
|||||||
glAccountTree[0].children.push(new GLAccountNode('INCOME'));
|
glAccountTree[0].children.push(new GLAccountNode('INCOME'));
|
||||||
glAccountTree[0].children.push(new GLAccountNode('LIABILITY'));
|
glAccountTree[0].children.push(new GLAccountNode('LIABILITY'));
|
||||||
|
|
||||||
|
// Sort by parent id (so that child nodes can be added properly)
|
||||||
glAccountData.sort((glAccountOne: any, glAccountTwo: any) => {
|
glAccountData.sort((glAccountOne: any, glAccountTwo: any) => {
|
||||||
if (!glAccountOne.parentId) {
|
if (!glAccountOne.parentId) {
|
||||||
glAccountOne.parentId = 0;
|
glAccountOne.parentId = 0;
|
||||||
@@ -41,11 +62,14 @@ export class GlAccountTreeService {
|
|||||||
|
|
||||||
const glAccounts: GLAccountNode[] = [];
|
const glAccounts: GLAccountNode[] = [];
|
||||||
|
|
||||||
|
// Add gl accounts to any array where index for each is denoted by its id
|
||||||
for (const glAccount of glAccountData) {
|
for (const glAccount of glAccountData) {
|
||||||
glAccounts[glAccount.id] =
|
glAccounts[glAccount.id] =
|
||||||
new GLAccountNode(glAccount.name, glAccount.glCode, glAccount.type.value, glAccount.usage.value, glAccount.manualEntriesAllowed, glAccount.description);
|
new GLAccountNode(glAccount.name, glAccount.glCode, glAccount.type.value, glAccount.usage.value, glAccount.manualEntriesAllowed, glAccount.description);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Construct gl account tree by adding all nodes belonging to headers (with parent id = 0) by their type,
|
||||||
|
// and rest as children to respective parent nodes.
|
||||||
for (const glAccount of glAccountData) {
|
for (const glAccount of glAccountData) {
|
||||||
if (glAccount.parentId === 0) {
|
if (glAccount.parentId === 0) {
|
||||||
if (glAccount.type.value === 'ASSET') {
|
if (glAccount.type.value === 'ASSET') {
|
||||||
|
|||||||
+19
-14
@@ -1,18 +1,23 @@
|
|||||||
<div fxLayout="row" fxLayoutAlign="end" fxLayoutGap="2%" fxLayout.lt-md="column" class="container m-b-20">
|
<div fxLayout="row" fxLayoutAlign="end" fxLayoutGap="2%" fxLayout.lt-md="column" class="container m-b-20">
|
||||||
<button mat-raised-button color="primary" *ngIf="glAccount.usage.value === 'HEADER'" [routerLink]="['/accounting/chart-of-accounts/gl-accounts/create']" [queryParams]="{ parent: glAccount.id, accountType: glAccount.type.id }">
|
<button mat-raised-button color="primary" *ngIf="glAccount.usage.value === 'HEADER'" [routerLink]="['/accounting/chart-of-accounts/gl-accounts/create']" [queryParams]="{ parent: glAccount.id, accountType: glAccount.type.id }">
|
||||||
<mat-icon>add</mat-icon> Subledger Account
|
<fa-icon icon="plus"></fa-icon>
|
||||||
|
Subledger Account
|
||||||
</button>
|
</button>
|
||||||
<button mat-raised-button color="primary" [routerLink]="['/accounting/chart-of-accounts/gl-accounts/view', glAccount.id, 'edit']">
|
<button mat-raised-button color="primary" [routerLink]="['edit']">
|
||||||
<mat-icon>edit</mat-icon> Edit
|
<fa-icon icon="edit"></fa-icon>
|
||||||
|
Edit
|
||||||
</button>
|
</button>
|
||||||
<button mat-raised-button color="warn" *ngIf="!glAccount.disabled" (click)="changeGlAccountState()">
|
<button mat-raised-button color="warn" *ngIf="!glAccount.disabled" (click)="changeGlAccountState()">
|
||||||
<mat-icon>lock</mat-icon> Disable
|
<fa-icon icon="lock"></fa-icon>
|
||||||
|
Disable
|
||||||
</button>
|
</button>
|
||||||
<button mat-raised-button color="accent" *ngIf="glAccount.disabled" (click)="changeGlAccountState()">
|
<button mat-raised-button color="accent" *ngIf="glAccount.disabled" (click)="changeGlAccountState()">
|
||||||
<mat-icon>lock_open</mat-icon> Enable
|
<fa-icon icon="lock-open"></fa-icon>
|
||||||
|
Enable
|
||||||
</button>
|
</button>
|
||||||
<button mat-raised-button color="warn" (click)="deleteGlAccount()">
|
<button mat-raised-button color="warn" (click)="deleteGlAccount()">
|
||||||
<mat-icon>delete</mat-icon> Delete
|
<fa-icon icon="trash"></fa-icon>
|
||||||
|
Delete
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -29,7 +34,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div fxFlex="50%">
|
<div fxFlex="50%">
|
||||||
{{ glAccount.type.value }}
|
{{ glAccount.type?.value }}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div fxFlex="50%" class="header">
|
<div fxFlex="50%" class="header">
|
||||||
@@ -40,19 +45,19 @@
|
|||||||
{{ glAccount.glCode }}
|
{{ glAccount.glCode }}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div fxFlex="50%" class="header">
|
<div fxFlex="50%" class="header" *ngIf="glAccount.parent">
|
||||||
Parent Account Name
|
Parent Account Name
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div fxFlex="50%">
|
<div fxFlex="50%" *ngIf="glAccount.parent">
|
||||||
{{ glAccount.parent.name }}
|
{{ glAccount.parent.name }}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div fxFlex="50%" class="header">
|
<div fxFlex="50%" class="header" *ngIf="glAccount.tagId.id">
|
||||||
Tag
|
Tag
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div fxFlex="50%">
|
<div fxFlex="50%" *ngIf="glAccount.tagId.id">
|
||||||
{{ glAccount.tagId.name }}
|
{{ glAccount.tagId.name }}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -61,7 +66,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div fxFlex="50%">
|
<div fxFlex="50%">
|
||||||
{{ glAccount.usage.value }}
|
{{ glAccount.usage?.value }}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div fxFlex="50%" class="header">
|
<div fxFlex="50%" class="header">
|
||||||
@@ -72,11 +77,11 @@
|
|||||||
{{ glAccount.manualEntriesAllowed }}
|
{{ glAccount.manualEntriesAllowed }}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div fxFlex="50%" class="header">
|
<div fxFlex="50%" class="header" *ngIf="glAccount.description">
|
||||||
Description
|
Description
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div fxFlex="50%">
|
<div fxFlex="50%" *ngIf="glAccount.description">
|
||||||
{{ glAccount.description }}
|
{{ glAccount.description }}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -1,14 +1,14 @@
|
|||||||
.container {
|
.container {
|
||||||
max-width: 37rem;
|
max-width: 37rem;
|
||||||
}
|
|
||||||
|
|
||||||
.content {
|
.content {
|
||||||
div {
|
div {
|
||||||
margin: 1rem 0;
|
margin: 1rem 0;
|
||||||
word-wrap: break-word;
|
word-wrap: break-word;
|
||||||
}
|
|
||||||
|
|
||||||
.header {
|
&.header {
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,17 @@
|
|||||||
|
/** Angular Imports */
|
||||||
import { Component, OnInit } from '@angular/core';
|
import { Component, OnInit } from '@angular/core';
|
||||||
import { ActivatedRoute, Router } from '@angular/router';
|
import { ActivatedRoute, Router } from '@angular/router';
|
||||||
import { MatDialog } from '@angular/material';
|
import { MatDialog } from '@angular/material';
|
||||||
|
|
||||||
|
/** Custom Components */
|
||||||
import { DeleteDialogComponent } from '../../../shared/delete-dialog/delete-dialog.component';
|
import { DeleteDialogComponent } from '../../../shared/delete-dialog/delete-dialog.component';
|
||||||
|
|
||||||
|
/** Custom Services */
|
||||||
import { AccountingService } from '../../accounting.service';
|
import { AccountingService } from '../../accounting.service';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* View gl account component.
|
||||||
|
*/
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'mifosx-view-gl-account',
|
selector: 'mifosx-view-gl-account',
|
||||||
templateUrl: './view-gl-account.component.html',
|
templateUrl: './view-gl-account.component.html',
|
||||||
@@ -12,22 +19,32 @@ import { AccountingService } from '../../accounting.service';
|
|||||||
})
|
})
|
||||||
export class ViewGlAccountComponent implements OnInit {
|
export class ViewGlAccountComponent implements OnInit {
|
||||||
|
|
||||||
|
/** GL Account. */
|
||||||
glAccount: any;
|
glAccount: any;
|
||||||
|
|
||||||
constructor(private route: ActivatedRoute,
|
/**
|
||||||
private accountingService: AccountingService,
|
* Retrieves the gl account data from `resolve`.
|
||||||
|
* @param {AccountingService} accountingService Accounting Service.
|
||||||
|
* @param {ActivatedRoute} route Activated Route.
|
||||||
|
* @param {Router} router Router for navigation.
|
||||||
|
* @param {MatDialog} dialog Dialog reference.
|
||||||
|
*/
|
||||||
|
constructor(private accountingService: AccountingService,
|
||||||
|
private route: ActivatedRoute,
|
||||||
private router: Router,
|
private router: Router,
|
||||||
public dialog: MatDialog) {
|
public dialog: MatDialog) {
|
||||||
this.route.data.subscribe((data: { glAccount: any }) => {
|
this.route.data.subscribe((data: { glAccountAndChartOfAccountsTemplate: any }) => {
|
||||||
this.glAccount = data.glAccount;
|
this.glAccount = data.glAccountAndChartOfAccountsTemplate;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deletes the gl account and redirects to chart of accounts.
|
||||||
|
*/
|
||||||
deleteGlAccount() {
|
deleteGlAccount() {
|
||||||
// TODO: (Validation) gl account cannot be deleted if it has transactions logged against it
|
|
||||||
const deleteGlAccountDialogRef = this.dialog.open(DeleteDialogComponent, {
|
const deleteGlAccountDialogRef = this.dialog.open(DeleteDialogComponent, {
|
||||||
data: { deleteContext: `gl account ${this.glAccount.id}` }
|
data: { deleteContext: `gl account ${this.glAccount.id}` }
|
||||||
});
|
});
|
||||||
@@ -41,6 +58,9 @@ export class ViewGlAccountComponent implements OnInit {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Changes state of gl account. (enabled/disabled)
|
||||||
|
*/
|
||||||
changeGlAccountState() {
|
changeGlAccountState() {
|
||||||
this.accountingService.updateGlAccount(this.glAccount.id, { disabled: !this.glAccount.disabled })
|
this.accountingService.updateGlAccount(this.glAccount.id, { disabled: !this.glAccount.disabled })
|
||||||
.subscribe((response: any) => {
|
.subscribe((response: any) => {
|
||||||
|
|||||||
@@ -1,38 +0,0 @@
|
|||||||
import { Injectable } from '@angular/core';
|
|
||||||
import { Resolve, ActivatedRouteSnapshot } from '@angular/router';
|
|
||||||
|
|
||||||
import { Observable } from 'rxjs';
|
|
||||||
import { map } from 'rxjs/operators';
|
|
||||||
|
|
||||||
import { AccountingService } from '../../accounting.service';
|
|
||||||
|
|
||||||
@Injectable()
|
|
||||||
export class ViewGlAccountResolver implements Resolve<Object> {
|
|
||||||
|
|
||||||
constructor(private accountingService: AccountingService) {}
|
|
||||||
|
|
||||||
resolve(route: ActivatedRouteSnapshot): Observable<any> {
|
|
||||||
const id = route.paramMap.get('id');
|
|
||||||
|
|
||||||
return this.accountingService.getGlAccount(id, true).pipe(map((glAccountData: any) => {
|
|
||||||
let accountOptions = [];
|
|
||||||
switch (glAccountData.type.value) {
|
|
||||||
case 'ASSET': accountOptions = glAccountData.assetHeaderAccountOptions;
|
|
||||||
break;
|
|
||||||
case 'EQUITY': accountOptions = glAccountData.equityHeaderAccountOptions;
|
|
||||||
break;
|
|
||||||
case 'EXPENSE': accountOptions = glAccountData.expenseHeaderAccountOptions;
|
|
||||||
break;
|
|
||||||
case 'INCOME': accountOptions = glAccountData.incomeHeaderAccountOptions;
|
|
||||||
break;
|
|
||||||
case 'LIABILITY': accountOptions = glAccountData.liabilityHeaderAccountOptions;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
glAccountData.parent = accountOptions.find((accountOption: any) => {
|
|
||||||
return accountOption.id === glAccountData.parentId;
|
|
||||||
});
|
|
||||||
return glAccountData;
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,12 +1,14 @@
|
|||||||
<div class="container m-b-20" fxLayout="row" fxLayoutAlign="end" fxLayoutGap="20px">
|
<div class="container m-b-20" fxLayout="row" fxLayoutAlign="end" fxLayoutGap="20px">
|
||||||
<button mat-raised-button color="primary" [routerLink]="['/accounting/closing-entries/create']">
|
<button mat-raised-button color="primary" [routerLink]="['create']">
|
||||||
<mat-icon>add</mat-icon> Create Closure
|
<fa-icon icon="plus"></fa-icon>
|
||||||
|
Create Closure
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="container" fxLayout="row wrap" fxLayoutGap="2%" fxLayout.lt-md="column">
|
<div class="container" fxLayout="row">
|
||||||
<mat-form-field fxFlex>
|
<mat-form-field fxFlex>
|
||||||
<input matInput placeholder="Office Name" [formControl]="officeName" [matAutocomplete]="officeNameAutocomplete">
|
<mat-label>Office Name</mat-label>
|
||||||
|
<input matInput [formControl]="officeName" [matAutocomplete]="officeNameAutocomplete">
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -44,7 +46,7 @@
|
|||||||
</ng-container>
|
</ng-container>
|
||||||
|
|
||||||
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
|
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
|
||||||
<tr mat-row *matRowDef="let row; columns: displayedColumns;" [routerLink]="['/accounting/closing-entries/view', row.id]"></tr>
|
<tr mat-row *matRowDef="let row; columns: displayedColumns;" [routerLink]="['view', row.id]"></tr>
|
||||||
|
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +1,15 @@
|
|||||||
|
/** Angular Imports */
|
||||||
import { Component, OnInit, ViewChild } from '@angular/core';
|
import { Component, OnInit, ViewChild } from '@angular/core';
|
||||||
import { MatPaginator, MatSort, MatTableDataSource } from '@angular/material';
|
import { MatPaginator, MatSort, MatTableDataSource } from '@angular/material';
|
||||||
import { FormControl } from '@angular/forms';
|
import { FormControl } from '@angular/forms';
|
||||||
import { startWith, map, tap } from 'rxjs/operators';
|
import { ActivatedRoute } from '@angular/router';
|
||||||
|
|
||||||
import { AccountingService } from '../accounting.service';
|
/** rxjs Imports */
|
||||||
|
import { startWith, map } from 'rxjs/operators';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Closing entries component.
|
||||||
|
*/
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'mifosx-closing-entries',
|
selector: 'mifosx-closing-entries',
|
||||||
templateUrl: './closing-entries.component.html',
|
templateUrl: './closing-entries.component.html',
|
||||||
@@ -12,52 +17,84 @@ import { AccountingService } from '../accounting.service';
|
|||||||
})
|
})
|
||||||
export class ClosingEntriesComponent implements OnInit {
|
export class ClosingEntriesComponent implements OnInit {
|
||||||
|
|
||||||
|
/** Columns to be displayed in closing entries table. */
|
||||||
displayedColumns: string[] = ['officeName', 'closingDate', 'comments', 'createdByUsername'];
|
displayedColumns: string[] = ['officeName', 'closingDate', 'comments', 'createdByUsername'];
|
||||||
dataSource: any;
|
/** Data source for closing entries table. */
|
||||||
|
dataSource: MatTableDataSource<any>;
|
||||||
|
/** Office name filter form control. */
|
||||||
officeName = new FormControl();
|
officeName = new FormControl();
|
||||||
|
/** Office data. */
|
||||||
officeData: any;
|
officeData: any;
|
||||||
|
/** Filtered office data for autocomplete. */
|
||||||
filteredOfficeData: any;
|
filteredOfficeData: any;
|
||||||
|
/** GL Account closure data. */
|
||||||
|
glAccountClosureData: any;
|
||||||
|
|
||||||
|
/** Paginator for closing entries table. */
|
||||||
@ViewChild(MatPaginator) paginator: MatPaginator;
|
@ViewChild(MatPaginator) paginator: MatPaginator;
|
||||||
|
/** Sorter for closing entries table. */
|
||||||
@ViewChild(MatSort) sort: MatSort;
|
@ViewChild(MatSort) sort: MatSort;
|
||||||
|
|
||||||
constructor(private accountingService: AccountingService) { }
|
/**
|
||||||
|
* Retrieves the offices and gl account closures data from `resolve`.
|
||||||
ngOnInit() {
|
* @param {ActivatedRoute} route Activated Route.
|
||||||
this.getOffices();
|
*/
|
||||||
this.applyFilter();
|
constructor(private route: ActivatedRoute) {
|
||||||
this.getAccountingClosures();
|
this.route.data.subscribe((data: {
|
||||||
|
offices: any,
|
||||||
|
glAccountClosures: any
|
||||||
|
}) => {
|
||||||
|
this.officeData = data.offices;
|
||||||
|
this.glAccountClosureData = data.glAccountClosures;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the filter and closing entries table.
|
||||||
|
*/
|
||||||
|
ngOnInit() {
|
||||||
|
this.applyFilter();
|
||||||
|
this.setFilteredOffices();
|
||||||
|
this.setAccountingClosures();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Filters data in closing entries table based on office name.
|
||||||
|
*/
|
||||||
applyFilter() {
|
applyFilter() {
|
||||||
this.officeName.valueChanges.subscribe((filterValue: string) => {
|
this.officeName.valueChanges.subscribe((filterValue: string) => {
|
||||||
this.dataSource.filter = filterValue.trim().toLowerCase();
|
this.dataSource.filter = filterValue.trim().toLowerCase();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
getAccountingClosures() {
|
/**
|
||||||
this.accountingService.getAccountingClosures().subscribe((glAccountClosureData: any) => {
|
* Initializes the data source, paginator and sorter for closing entries table.
|
||||||
this.dataSource = new MatTableDataSource(glAccountClosureData);
|
*/
|
||||||
this.dataSource.paginator = this.paginator;
|
setAccountingClosures() {
|
||||||
this.dataSource.sort = this.sort;
|
this.dataSource = new MatTableDataSource(this.glAccountClosureData);
|
||||||
});
|
this.dataSource.paginator = this.paginator;
|
||||||
|
this.dataSource.sort = this.sort;
|
||||||
}
|
}
|
||||||
|
|
||||||
getOffices() {
|
/**
|
||||||
this.accountingService.getOffices().subscribe(officeData => {
|
* Sets filtered offices for autocomplete.
|
||||||
this.officeData = officeData;
|
*/
|
||||||
this.filteredOfficeData = this.officeName.valueChanges
|
setFilteredOffices() {
|
||||||
.pipe(
|
this.filteredOfficeData = this.officeName.valueChanges
|
||||||
startWith(''),
|
.pipe(
|
||||||
map((office: any) => typeof office === 'string' ? office : office.name),
|
startWith(''),
|
||||||
map((officeName: string) => officeName ? this.filterOfficeAutocompleteData(this.officeData, officeName) : this.officeData)
|
map((office: any) => typeof office === 'string' ? office : office.name),
|
||||||
);
|
map((officeName: string) => officeName ? this.filterOfficeAutocompleteData(officeName) : this.officeData)
|
||||||
});
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private filterOfficeAutocompleteData(officeData: any, officeName: string): any {
|
/**
|
||||||
return officeData.filter((office: any) => office.name.toLowerCase().includes(officeName.toLowerCase()));
|
* Filters offices.
|
||||||
|
* @param {string} officeName Office name to filter office by.
|
||||||
|
* @returns {any} Filtered offices.
|
||||||
|
*/
|
||||||
|
private filterOfficeAutocompleteData(officeName: string): any {
|
||||||
|
return this.officeData.filter((office: any) => office.name.toLowerCase().includes(officeName.toLowerCase()));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,30 @@
|
|||||||
|
/** Angular Imports */
|
||||||
|
import { Injectable } from '@angular/core';
|
||||||
|
import { Resolve } from '@angular/router';
|
||||||
|
|
||||||
|
/** rxjs Imports */
|
||||||
|
import { Observable } from 'rxjs';
|
||||||
|
|
||||||
|
/** Custom Services */
|
||||||
|
import { AccountingService } from '../accounting.service';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Closing entries data resolver.
|
||||||
|
*/
|
||||||
|
@Injectable()
|
||||||
|
export class ClosingEntriesResolver implements Resolve<Object> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {AccountingService} accountingService Accounting service.
|
||||||
|
*/
|
||||||
|
constructor(private accountingService: AccountingService) {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the gl account closures data.
|
||||||
|
* @returns {Observable<any>}
|
||||||
|
*/
|
||||||
|
resolve(): Observable<any> {
|
||||||
|
return this.accountingService.getAccountingClosures();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
/** Angular Imports */
|
||||||
|
import { Injectable } from '@angular/core';
|
||||||
|
import { Resolve, ActivatedRouteSnapshot } from '@angular/router';
|
||||||
|
|
||||||
|
/** rxjs Imports */
|
||||||
|
import { Observable } from 'rxjs';
|
||||||
|
|
||||||
|
/** Custom Services */
|
||||||
|
import { AccountingService } from '../accounting.service';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Closing entry data resolver.
|
||||||
|
*/
|
||||||
|
@Injectable()
|
||||||
|
export class ClosingEntryResolver implements Resolve<Object> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {AccountingService} accountingService Accounting service.
|
||||||
|
*/
|
||||||
|
constructor(private accountingService: AccountingService) {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the gl account closure data.
|
||||||
|
* @returns {Observable<any>}
|
||||||
|
*/
|
||||||
|
resolve(route: ActivatedRouteSnapshot): Observable<any> {
|
||||||
|
const glAccountClosureId = route.paramMap.get('id');
|
||||||
|
return this.accountingService.getAccountingClosure(glAccountClosureId);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -9,21 +9,30 @@
|
|||||||
<div fxLayout="column">
|
<div fxLayout="column">
|
||||||
|
|
||||||
<mat-form-field>
|
<mat-form-field>
|
||||||
<mat-select placeholder="Office" required formControlName="officeId">
|
<mat-label>Office</mat-label>
|
||||||
|
<mat-select required formControlName="officeId">
|
||||||
<mat-option *ngFor="let office of officeData" [value]="office.id">
|
<mat-option *ngFor="let office of officeData" [value]="office.id">
|
||||||
{{ office.name }}
|
{{ office.name }}
|
||||||
</mat-option>
|
</mat-option>
|
||||||
</mat-select>
|
</mat-select>
|
||||||
|
<mat-error *ngIf="accountingClosureForm.controls.officeId.hasError('required')">
|
||||||
|
Office is <strong>required</strong>
|
||||||
|
</mat-error>
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
|
|
||||||
<mat-form-field>
|
<mat-form-field>
|
||||||
<input matInput [min]="minDate" [max]="maxDate" [matDatepicker]="closingDatePicker" placeholder="Closing Date" required formControlName="closingDate">
|
<mat-label>Closing Date</mat-label>
|
||||||
|
<input matInput [min]="minDate" [max]="maxDate" [matDatepicker]="closingDatePicker" required formControlName="closingDate">
|
||||||
<mat-datepicker-toggle matSuffix [for]="closingDatePicker"></mat-datepicker-toggle>
|
<mat-datepicker-toggle matSuffix [for]="closingDatePicker"></mat-datepicker-toggle>
|
||||||
<mat-datepicker #closingDatePicker></mat-datepicker>
|
<mat-datepicker #closingDatePicker></mat-datepicker>
|
||||||
|
<mat-error *ngIf="accountingClosureForm.controls.closingDate.hasError('required')">
|
||||||
|
Closing Date is <strong>required</strong>
|
||||||
|
</mat-error>
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
|
|
||||||
<mat-form-field>
|
<mat-form-field>
|
||||||
<textarea matInput placeholder="Comments" formControlName="comments"></textarea>
|
<mat-label>Comments</mat-label>
|
||||||
|
<textarea matInput formControlName="comments"></textarea>
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
@@ -31,8 +40,8 @@
|
|||||||
</mat-card-content>
|
</mat-card-content>
|
||||||
|
|
||||||
<mat-card-actions fxLayout="row" fxLayout.xs="column" fxLayoutAlign="center" fxLayoutGap="5px">
|
<mat-card-actions fxLayout="row" fxLayout.xs="column" fxLayoutAlign="center" fxLayoutGap="5px">
|
||||||
<button type="button" mat-raised-button [routerLink]="['/accounting/closing-entries']">Cancel</button>
|
<button type="button" mat-raised-button [routerLink]="['../']">Cancel</button>
|
||||||
<button mat-raised-button color="primary">Submit</button>
|
<button mat-raised-button color="primary" [disabled]="!accountingClosureForm.valid">Submit</button>
|
||||||
</mat-card-actions>
|
</mat-card-actions>
|
||||||
|
|
||||||
</form>
|
</form>
|
||||||
|
|||||||
@@ -1,9 +1,14 @@
|
|||||||
|
/** Angular Imports */
|
||||||
import { Component, OnInit } from '@angular/core';
|
import { Component, OnInit } from '@angular/core';
|
||||||
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
|
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
|
||||||
import { Router } from '@angular/router';
|
import { Router, ActivatedRoute } from '@angular/router';
|
||||||
|
|
||||||
|
/** Custom Services */
|
||||||
import { AccountingService } from '../../accounting.service';
|
import { AccountingService } from '../../accounting.service';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create closure component.
|
||||||
|
*/
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'mifosx-create-closure',
|
selector: 'mifosx-create-closure',
|
||||||
templateUrl: './create-closure.component.html',
|
templateUrl: './create-closure.component.html',
|
||||||
@@ -11,22 +16,41 @@ import { AccountingService } from '../../accounting.service';
|
|||||||
})
|
})
|
||||||
export class CreateClosureComponent implements OnInit {
|
export class CreateClosureComponent implements OnInit {
|
||||||
|
|
||||||
// TODO: Validations, Hints
|
/** Minimum closing date allowed. */
|
||||||
|
|
||||||
minDate = new Date(2000, 0, 1);
|
minDate = new Date(2000, 0, 1);
|
||||||
|
/** Maximum closing date allowed. */
|
||||||
maxDate = new Date();
|
maxDate = new Date();
|
||||||
|
/** Accounting closure form. */
|
||||||
accountingClosureForm: FormGroup;
|
accountingClosureForm: FormGroup;
|
||||||
|
/** Office data. */
|
||||||
officeData: any;
|
officeData: any;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the offices data from `resolve`.
|
||||||
|
* @param {FormBuilder} formBuilder Form Builder.
|
||||||
|
* @param {AccountingService} accountingService Accounting Service.
|
||||||
|
* @param {ActivatedRoute} route Activated Route.
|
||||||
|
* @param {Router} router Router for navigation.
|
||||||
|
*/
|
||||||
constructor(private formBuilder: FormBuilder,
|
constructor(private formBuilder: FormBuilder,
|
||||||
private accountingService: AccountingService,
|
private accountingService: AccountingService,
|
||||||
private router: Router) { }
|
private route: ActivatedRoute,
|
||||||
|
private router: Router) {
|
||||||
ngOnInit() {
|
this.route.data.subscribe((data: { offices: any }) => {
|
||||||
this.createAccountingClosureForm();
|
this.officeData = data.offices;
|
||||||
this.getOffices();
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates the accounting closure form.
|
||||||
|
*/
|
||||||
|
ngOnInit() {
|
||||||
|
this.createAccountingClosureForm();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates the accounting closure form.
|
||||||
|
*/
|
||||||
createAccountingClosureForm() {
|
createAccountingClosureForm() {
|
||||||
this.accountingClosureForm = this.formBuilder.group({
|
this.accountingClosureForm = this.formBuilder.group({
|
||||||
'officeId': ['', Validators.required],
|
'officeId': ['', Validators.required],
|
||||||
@@ -35,20 +59,29 @@ export class CreateClosureComponent implements OnInit {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
getOffices() {
|
/**
|
||||||
this.accountingService.getOffices().subscribe(officeData => {
|
* Submits the accounting closure form and creates accounting closure,
|
||||||
this.officeData = officeData;
|
* if successful redirects to view created closure.
|
||||||
});
|
*/
|
||||||
}
|
|
||||||
|
|
||||||
submit() {
|
submit() {
|
||||||
const accountingClosure = this.accountingClosureForm.value;
|
const accountingClosure = this.accountingClosureForm.value;
|
||||||
// TODO: Update once language and date settings are setup
|
// TODO: Update once language and date settings are setup
|
||||||
accountingClosure.locale = 'en';
|
accountingClosure.locale = 'en';
|
||||||
accountingClosure.dateFormat = 'dd MMMM yyyy';
|
accountingClosure.dateFormat = 'yyyy-MM-dd';
|
||||||
accountingClosure.closingDate = '4 August 2018';
|
if (accountingClosure.closingDate instanceof Date) {
|
||||||
|
let day = accountingClosure.closingDate.getDate();
|
||||||
|
let month = accountingClosure.closingDate.getMonth() + 1;
|
||||||
|
const year = accountingClosure.closingDate.getFullYear();
|
||||||
|
if (day < 10) {
|
||||||
|
day = `0${day}`;
|
||||||
|
}
|
||||||
|
if (month < 10) {
|
||||||
|
month = `0${month}`;
|
||||||
|
}
|
||||||
|
accountingClosure.closingDate = `${year}-${month}-${day}`;
|
||||||
|
}
|
||||||
this.accountingService.createAccountingClosure(accountingClosure).subscribe((response: any) => {
|
this.accountingService.createAccountingClosure(accountingClosure).subscribe((response: any) => {
|
||||||
this.router.navigate(['/accounting/closing-entries/view', response.resourceId]);
|
this.router.navigate(['../view', response.resourceId], { relativeTo: this.route });
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -9,7 +9,8 @@
|
|||||||
<div fxLayout="column">
|
<div fxLayout="column">
|
||||||
|
|
||||||
<mat-form-field>
|
<mat-form-field>
|
||||||
<mat-select placeholder="Office" required formControlName="officeId">
|
<mat-label>Office</mat-label>
|
||||||
|
<mat-select required formControlName="officeId">
|
||||||
<mat-option *ngFor="let office of officeData" [value]="office.id">
|
<mat-option *ngFor="let office of officeData" [value]="office.id">
|
||||||
{{ office.name }}
|
{{ office.name }}
|
||||||
</mat-option>
|
</mat-option>
|
||||||
@@ -17,13 +18,15 @@
|
|||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
|
|
||||||
<mat-form-field>
|
<mat-form-field>
|
||||||
<input matInput [matDatepicker]="closingDatePicker" placeholder="Closing Date" required formControlName="closingDate">
|
<mat-label>Closing Date</mat-label>
|
||||||
|
<input matInput [matDatepicker]="closingDatePicker" required formControlName="closingDate">
|
||||||
<mat-datepicker-toggle matSuffix [for]="closingDatePicker"></mat-datepicker-toggle>
|
<mat-datepicker-toggle matSuffix [for]="closingDatePicker"></mat-datepicker-toggle>
|
||||||
<mat-datepicker #closingDatePicker></mat-datepicker>
|
<mat-datepicker #closingDatePicker></mat-datepicker>
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
|
|
||||||
<mat-form-field>
|
<mat-form-field>
|
||||||
<textarea matInput placeholder="Comments" formControlName="comments"></textarea>
|
<mat-label>Comments</mat-label>
|
||||||
|
<textarea matInput formControlName="comments"></textarea>
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
@@ -31,8 +34,8 @@
|
|||||||
</mat-card-content>
|
</mat-card-content>
|
||||||
|
|
||||||
<mat-card-actions fxLayout="row" fxLayout.xs="column" fxLayoutAlign="center" fxLayoutGap="5px">
|
<mat-card-actions fxLayout="row" fxLayout.xs="column" fxLayoutAlign="center" fxLayoutGap="5px">
|
||||||
<button type="button" mat-raised-button [routerLink]="['/accounting/closing-entries/view', accountingClosure?.id]">Cancel</button>
|
<button type="button" mat-raised-button [routerLink]="['../']">Cancel</button>
|
||||||
<button mat-raised-button color="primary">Submit</button>
|
<button mat-raised-button color="primary" [disabled]="accountingClosureForm.pristine">Submit</button>
|
||||||
</mat-card-actions>
|
</mat-card-actions>
|
||||||
|
|
||||||
</form>
|
</form>
|
||||||
|
|||||||
@@ -1,9 +1,14 @@
|
|||||||
|
/** Angular Imports */
|
||||||
import { Component, OnInit } from '@angular/core';
|
import { Component, OnInit } from '@angular/core';
|
||||||
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
|
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
|
||||||
import { Router, ActivatedRoute } from '@angular/router';
|
import { Router, ActivatedRoute } from '@angular/router';
|
||||||
|
|
||||||
|
/** Custom Services */
|
||||||
import { AccountingService } from '../../accounting.service';
|
import { AccountingService } from '../../accounting.service';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Edit closure component.
|
||||||
|
*/
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'mifosx-edit-closure',
|
selector: 'mifosx-edit-closure',
|
||||||
templateUrl: './edit-closure.component.html',
|
templateUrl: './edit-closure.component.html',
|
||||||
@@ -11,35 +16,40 @@ import { AccountingService } from '../../accounting.service';
|
|||||||
})
|
})
|
||||||
export class EditClosureComponent implements OnInit {
|
export class EditClosureComponent implements OnInit {
|
||||||
|
|
||||||
// TODO: Update once language and date settings are setup
|
/** Accounting closure form. */
|
||||||
|
|
||||||
accountingClosureForm: FormGroup;
|
accountingClosureForm: FormGroup;
|
||||||
accountingClosureId: number;
|
/** GL Account closure. */
|
||||||
accountingClosure: any;
|
glAccountClosure: any;
|
||||||
|
/** Office data. */
|
||||||
officeData: any;
|
officeData: any;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the gl account closure data from `resolve`.
|
||||||
|
* @param {FormBuilder} formBuilder Form Builder.
|
||||||
|
* @param {AccountingService} accountingService Accounting Service.
|
||||||
|
* @param {ActivatedRoute} route Activated Route.
|
||||||
|
* @param {Router} router Router for navigation.
|
||||||
|
*/
|
||||||
constructor(private formBuilder: FormBuilder,
|
constructor(private formBuilder: FormBuilder,
|
||||||
private accountingService: AccountingService,
|
private accountingService: AccountingService,
|
||||||
private router: Router,
|
private route: ActivatedRoute,
|
||||||
private route: ActivatedRoute) { }
|
private router: Router) {
|
||||||
|
this.route.data.subscribe((data: { glAccountClosure: any }) => {
|
||||||
|
this.glAccountClosure = data.glAccountClosure;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates and sets accounting closure form.
|
||||||
|
*/
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
this.accountingClosureId = Number(this.route.snapshot.paramMap.get('id'));
|
|
||||||
this.createAccountingClosureForm();
|
this.createAccountingClosureForm();
|
||||||
this.getAccountingClosure();
|
this.setAccountingClosure();
|
||||||
this.getOffices();
|
|
||||||
}
|
|
||||||
|
|
||||||
getAccountingClosure() {
|
|
||||||
this.accountingService.getAccountingClosure(this.accountingClosureId)
|
|
||||||
.subscribe((accountingClosure: any) => {
|
|
||||||
this.accountingClosure = accountingClosure;
|
|
||||||
this.accountingClosureForm.get('officeId').setValue(this.accountingClosure.officeId);
|
|
||||||
this.accountingClosureForm.get('closingDate').setValue(new Date());
|
|
||||||
this.accountingClosureForm.get('comments').setValue(this.accountingClosure.comments);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates accounting closure form.
|
||||||
|
*/
|
||||||
createAccountingClosureForm() {
|
createAccountingClosureForm() {
|
||||||
this.accountingClosureForm = this.formBuilder.group({
|
this.accountingClosureForm = this.formBuilder.group({
|
||||||
'officeId': [{ value: '', disabled: true }, Validators.required],
|
'officeId': [{ value: '', disabled: true }, Validators.required],
|
||||||
@@ -48,16 +58,26 @@ export class EditClosureComponent implements OnInit {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
getOffices() {
|
/**
|
||||||
this.accountingService.getOffices().subscribe(officeData => {
|
* Sets accounting closure form.
|
||||||
this.officeData = officeData;
|
*/
|
||||||
});
|
setAccountingClosure() {
|
||||||
|
this.officeData = [{ id: this.glAccountClosure.officeId, name: this.glAccountClosure.officeName }];
|
||||||
|
this.accountingClosureForm.get('officeId').setValue(this.glAccountClosure.officeId);
|
||||||
|
this.accountingClosureForm.get('closingDate').setValue(new Date(this.glAccountClosure.closingDate));
|
||||||
|
this.accountingClosureForm.get('comments').setValue(this.glAccountClosure.comments);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Submits the accounting closure form and updates accounting closure,
|
||||||
|
* if successful redirects to view updated closure.
|
||||||
|
*/
|
||||||
submit() {
|
submit() {
|
||||||
this.accountingService.updateAccountingClosure(this.accountingClosureId, { comments: this.accountingClosureForm.value.comments })
|
this.accountingService.updateAccountingClosure(this.glAccountClosure.id,
|
||||||
|
{ comments: this.accountingClosureForm.value.comments })
|
||||||
.subscribe((response: any) => {
|
.subscribe((response: any) => {
|
||||||
this.router.navigate(['/accounting/closing-entries/view', response.resourceId]);
|
this.router.navigate(['../../', response.resourceId], { relativeTo: this.route });
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,13 +1,15 @@
|
|||||||
<div fxLayout="row" fxLayoutAlign="end" fxLayoutGap="2%" fxLayout.lt-md="column" class="container m-b-20">
|
<div fxLayout="row" fxLayoutAlign="end" fxLayoutGap="2%" fxLayout.lt-md="column" class="container m-b-20">
|
||||||
<button mat-raised-button color="primary" [routerLink]="['/accounting/closing-entries/view', accountingClosure?.id, 'edit']">
|
<button mat-raised-button color="primary" [routerLink]="['edit']">
|
||||||
<mat-icon>edit</mat-icon> Edit
|
<fa-icon icon="edit"></fa-icon>
|
||||||
|
Edit
|
||||||
</button>
|
</button>
|
||||||
<button mat-raised-button color="warn" (click)="deleteAccountingClosure()">
|
<button mat-raised-button color="warn" (click)="deleteAccountingClosure()">
|
||||||
<mat-icon>delete</mat-icon> Delete
|
<fa-icon icon="trash"></fa-icon>
|
||||||
|
Delete
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="container" *ngIf="accountingClosure">
|
<div class="container" *ngIf="glAccountClosure">
|
||||||
|
|
||||||
<mat-card>
|
<mat-card>
|
||||||
|
|
||||||
@@ -20,7 +22,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div fxFlex="50%">
|
<div fxFlex="50%">
|
||||||
{{ accountingClosure.officeName }}
|
{{ glAccountClosure.officeName }}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div fxFlex="50%" class="header">
|
<div fxFlex="50%" class="header">
|
||||||
@@ -28,7 +30,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div fxFlex="50%">
|
<div fxFlex="50%">
|
||||||
{{ accountingClosure.closingDate }}
|
{{ glAccountClosure.closingDate }}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div fxFlex="50%" class="header">
|
<div fxFlex="50%" class="header">
|
||||||
@@ -36,7 +38,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div fxFlex="50%">
|
<div fxFlex="50%">
|
||||||
{{ accountingClosure.createdByUsername }}
|
{{ glAccountClosure.createdByUsername }}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div fxFlex="50%" class="header">
|
<div fxFlex="50%" class="header">
|
||||||
@@ -44,7 +46,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div fxFlex="50%">
|
<div fxFlex="50%">
|
||||||
{{ accountingClosure.lastUpdatedByUsername }}
|
{{ glAccountClosure.lastUpdatedByUsername }}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div fxFlex="50%" class="header">
|
<div fxFlex="50%" class="header">
|
||||||
@@ -52,7 +54,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div fxFlex="50%">
|
<div fxFlex="50%">
|
||||||
{{ accountingClosure.lastUpdatedDate }}
|
{{ glAccountClosure.lastUpdatedDate }}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div fxFlex="50%" class="header">
|
<div fxFlex="50%" class="header">
|
||||||
@@ -60,7 +62,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div fxFlex="50%">
|
<div fxFlex="50%">
|
||||||
{{ accountingClosure.createdDate }}
|
{{ glAccountClosure.createdDate }}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div fxFlex="50%" class="header">
|
<div fxFlex="50%" class="header">
|
||||||
@@ -68,7 +70,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div fxFlex="50%">
|
<div fxFlex="50%">
|
||||||
{{ accountingClosure.comments }}
|
{{ glAccountClosure.comments }}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,14 +1,14 @@
|
|||||||
.container {
|
.container {
|
||||||
max-width: 37rem;
|
max-width: 37rem;
|
||||||
}
|
|
||||||
|
|
||||||
.content {
|
.content {
|
||||||
div {
|
div {
|
||||||
margin: 1rem 0;
|
margin: 1rem 0;
|
||||||
word-wrap: break-word;
|
word-wrap: break-word;
|
||||||
}
|
|
||||||
|
|
||||||
.header {
|
&.header {
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,17 @@
|
|||||||
|
/** Angular Imports */
|
||||||
import { Component, OnInit } from '@angular/core';
|
import { Component, OnInit } from '@angular/core';
|
||||||
import { ActivatedRoute, Router } from '@angular/router';
|
import { ActivatedRoute, Router } from '@angular/router';
|
||||||
import { MatDialog } from '@angular/material';
|
import { MatDialog } from '@angular/material';
|
||||||
|
|
||||||
|
/** Custom Services */
|
||||||
import { AccountingService } from '../../accounting.service';
|
import { AccountingService } from '../../accounting.service';
|
||||||
|
|
||||||
|
/** Custom Components */
|
||||||
import { DeleteDialogComponent } from '../../../shared/delete-dialog/delete-dialog.component';
|
import { DeleteDialogComponent } from '../../../shared/delete-dialog/delete-dialog.component';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* View closure component.
|
||||||
|
*/
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'mifosx-view-closure',
|
selector: 'mifosx-view-closure',
|
||||||
templateUrl: './view-closure.component.html',
|
templateUrl: './view-closure.component.html',
|
||||||
@@ -12,33 +19,38 @@ import { DeleteDialogComponent } from '../../../shared/delete-dialog/delete-dial
|
|||||||
})
|
})
|
||||||
export class ViewClosureComponent implements OnInit {
|
export class ViewClosureComponent implements OnInit {
|
||||||
|
|
||||||
accountingClosureId: number;
|
/** GL Account closure. */
|
||||||
accountingClosure: any;
|
glAccountClosure: any;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the gl account closure data from `resolve`.
|
||||||
|
* @param {AccountingService} accountingService Accounting Service.
|
||||||
|
* @param {ActivatedRoute} route Activated Route.
|
||||||
|
* @param {Router} router Router for navigation.
|
||||||
|
* @param {MatDialog} dialog Dialog reference.
|
||||||
|
*/
|
||||||
constructor(private accountingService: AccountingService,
|
constructor(private accountingService: AccountingService,
|
||||||
private route: ActivatedRoute,
|
private route: ActivatedRoute,
|
||||||
private router: Router,
|
private router: Router,
|
||||||
public dialog: MatDialog) { }
|
public dialog: MatDialog) {
|
||||||
|
this.route.data.subscribe((data: { glAccountClosure: any }) => {
|
||||||
|
this.glAccountClosure = data.glAccountClosure;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
this.accountingClosureId = Number(this.route.snapshot.paramMap.get('id'));
|
|
||||||
this.getAccountingClosure();
|
|
||||||
}
|
|
||||||
|
|
||||||
getAccountingClosure() {
|
|
||||||
this.accountingService.getAccountingClosure(this.accountingClosureId)
|
|
||||||
.subscribe((accountingClosure: any) => {
|
|
||||||
this.accountingClosure = accountingClosure;
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deletes the gl account closure and redirects to closing entries.
|
||||||
|
*/
|
||||||
deleteAccountingClosure() {
|
deleteAccountingClosure() {
|
||||||
const deleteAccountingClosureDialogRef = this.dialog.open(DeleteDialogComponent, {
|
const deleteAccountingClosureDialogRef = this.dialog.open(DeleteDialogComponent, {
|
||||||
data: { deleteContext: `accounting closure ${this.accountingClosureId}` }
|
data: { deleteContext: `accounting closure ${this.glAccountClosure.id}` }
|
||||||
});
|
});
|
||||||
deleteAccountingClosureDialogRef.afterClosed().subscribe((response: any) => {
|
deleteAccountingClosureDialogRef.afterClosed().subscribe((response: any) => {
|
||||||
if (response.delete) {
|
if (response.delete) {
|
||||||
this.accountingService.deleteAccountingClosure(this.accountingClosureId)
|
this.accountingService.deleteAccountingClosure(this.glAccountClosure.id)
|
||||||
.subscribe(() => {
|
.subscribe(() => {
|
||||||
this.router.navigate(['/accounting/closing-entries']);
|
this.router.navigate(['/accounting/closing-entries']);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -0,0 +1,30 @@
|
|||||||
|
/** Angular Imports */
|
||||||
|
import { Injectable } from '@angular/core';
|
||||||
|
import { Resolve } from '@angular/router';
|
||||||
|
|
||||||
|
/** rxjs Imports */
|
||||||
|
import { Observable } from 'rxjs';
|
||||||
|
|
||||||
|
/** Custom Services */
|
||||||
|
import { AccountingService } from '../accounting.service';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Accounting rules associations data resolver.
|
||||||
|
*/
|
||||||
|
@Injectable()
|
||||||
|
export class AccountingRulesAssociationsResolver implements Resolve<Object> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {AccountingService} accountingService Accounting service.
|
||||||
|
*/
|
||||||
|
constructor(private accountingService: AccountingService) {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the accounting rules associations data.
|
||||||
|
* @returns {Observable<any>}
|
||||||
|
*/
|
||||||
|
resolve(): Observable<any> {
|
||||||
|
return this.accountingService.getAccountingRules(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
/** Angular Imports */
|
||||||
|
import { Injectable } from '@angular/core';
|
||||||
|
import { Resolve } from '@angular/router';
|
||||||
|
|
||||||
|
/** rxjs Imports */
|
||||||
|
import { Observable } from 'rxjs';
|
||||||
|
|
||||||
|
/** Custom Services */
|
||||||
|
import { AccountingService } from '../accounting.service';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Currencies data resolver.
|
||||||
|
*/
|
||||||
|
@Injectable()
|
||||||
|
export class CurrenciesResolver implements Resolve<Object> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {AccountingService} accountingService Accounting service.
|
||||||
|
*/
|
||||||
|
constructor(private accountingService: AccountingService) {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the currencies data.
|
||||||
|
* @returns {Observable<any>}
|
||||||
|
*/
|
||||||
|
resolve(): Observable<any> {
|
||||||
|
return this.accountingService.getCurrencies();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
/** Angular Imports */
|
||||||
|
import { Injectable } from '@angular/core';
|
||||||
|
import { Resolve } from '@angular/router';
|
||||||
|
|
||||||
|
/** rxjs Imports */
|
||||||
|
import { Observable } from 'rxjs';
|
||||||
|
|
||||||
|
/** Custom Services */
|
||||||
|
import { AccountingService } from '../accounting.service';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* GL accounts data resolver.
|
||||||
|
*/
|
||||||
|
@Injectable()
|
||||||
|
export class GlAccountsResolver implements Resolve<Object> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {AccountingService} accountingService Accounting service.
|
||||||
|
*/
|
||||||
|
constructor(private accountingService: AccountingService) {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the gl accounts data.
|
||||||
|
* @returns {Observable<any>}
|
||||||
|
*/
|
||||||
|
resolve(): Observable<any> {
|
||||||
|
return this.accountingService.getGlAccounts();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
/** Angular Imports */
|
||||||
|
import { Injectable } from '@angular/core';
|
||||||
|
import { Resolve } from '@angular/router';
|
||||||
|
|
||||||
|
/** rxjs Imports */
|
||||||
|
import { Observable } from 'rxjs';
|
||||||
|
|
||||||
|
/** Custom Services */
|
||||||
|
import { AccountingService } from '../accounting.service';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loan products data resolver.
|
||||||
|
*/
|
||||||
|
@Injectable()
|
||||||
|
export class LoanProductsResolver implements Resolve<Object> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {AccountingService} accountingService Accounting service.
|
||||||
|
*/
|
||||||
|
constructor(private accountingService: AccountingService) {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the loan products data.
|
||||||
|
* @returns {Observable<any>}
|
||||||
|
*/
|
||||||
|
resolve(): Observable<any> {
|
||||||
|
return this.accountingService.getLoanProducts();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
/** Angular Imports */
|
||||||
|
import { Injectable } from '@angular/core';
|
||||||
|
import { Resolve } from '@angular/router';
|
||||||
|
|
||||||
|
/** rxjs Imports */
|
||||||
|
import { Observable } from 'rxjs';
|
||||||
|
|
||||||
|
/** Custom Services */
|
||||||
|
import { AccountingService } from '../accounting.service';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Offices data resolver.
|
||||||
|
*/
|
||||||
|
@Injectable()
|
||||||
|
export class OfficesResolver implements Resolve<Object> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {AccountingService} accountingService Accounting service.
|
||||||
|
*/
|
||||||
|
constructor(private accountingService: AccountingService) {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the offices data.
|
||||||
|
* @returns {Observable<any>}
|
||||||
|
*/
|
||||||
|
resolve(): Observable<any> {
|
||||||
|
return this.accountingService.getOffices();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
/** Angular Imports */
|
||||||
|
import { Injectable } from '@angular/core';
|
||||||
|
import { Resolve } from '@angular/router';
|
||||||
|
|
||||||
|
/** rxjs Imports */
|
||||||
|
import { Observable } from 'rxjs';
|
||||||
|
|
||||||
|
/** Custom Services */
|
||||||
|
import { AccountingService } from '../accounting.service';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Payment types data resolver.
|
||||||
|
*/
|
||||||
|
@Injectable()
|
||||||
|
export class PaymentTypesResolver implements Resolve<Object> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {AccountingService} accountingService Accounting service.
|
||||||
|
*/
|
||||||
|
constructor(private accountingService: AccountingService) {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the payment types data.
|
||||||
|
* @returns {Observable<any>}
|
||||||
|
*/
|
||||||
|
resolve(): Observable<any> {
|
||||||
|
return this.accountingService.getPaymentTypes();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
/** Angular Imports */
|
||||||
|
import { Injectable } from '@angular/core';
|
||||||
|
import { Resolve } from '@angular/router';
|
||||||
|
|
||||||
|
/** rxjs Imports */
|
||||||
|
import { Observable } from 'rxjs';
|
||||||
|
|
||||||
|
/** Custom Services */
|
||||||
|
import { AccountingService } from '../accounting.service';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provisioning categories data resolver.
|
||||||
|
*/
|
||||||
|
@Injectable()
|
||||||
|
export class ProvisioningCategoriesResolver implements Resolve<Object> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {AccountingService} accountingService Accounting service.
|
||||||
|
*/
|
||||||
|
constructor(private accountingService: AccountingService) {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the Provisioning categories data.
|
||||||
|
* @returns {Observable<any>}
|
||||||
|
*/
|
||||||
|
resolve(): Observable<any> {
|
||||||
|
return this.accountingService.getProvisioningCategories();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,131 +1,178 @@
|
|||||||
<mat-card class="container">
|
<div class="container">
|
||||||
|
|
||||||
<form [formGroup]="journalEntryForm" (ngSubmit)="submit()">
|
<mat-card>
|
||||||
|
|
||||||
<mat-card-content>
|
<form [formGroup]="journalEntryForm" (ngSubmit)="submit()">
|
||||||
|
|
||||||
<div fxLayout="row wrap" fxLayoutGap="2%" fxLayout.lt-md="column">
|
<mat-card-content>
|
||||||
|
|
||||||
<mat-form-field fxFlex="48%">
|
<div fxLayout="row wrap" fxLayoutGap="2%" fxLayout.lt-md="column">
|
||||||
<mat-select placeholder="Office" required formControlName="officeId">
|
|
||||||
<mat-option *ngFor="let office of officeData" [value]="office.id">
|
|
||||||
{{ office.name }}
|
|
||||||
</mat-option>
|
|
||||||
</mat-select>
|
|
||||||
</mat-form-field>
|
|
||||||
|
|
||||||
<mat-form-field fxFlex="48%">
|
<mat-form-field fxFlex="48%">
|
||||||
<mat-select placeholder="Currency" required formControlName="currencyCode">
|
<mat-label>Office</mat-label>
|
||||||
<mat-option *ngFor="let currency of currencyData" [value]="currency.code">
|
<mat-select required formControlName="officeId">
|
||||||
{{ currency.displayLabel }}
|
<mat-option *ngFor="let office of officeData" [value]="office.id">
|
||||||
</mat-option>
|
{{ office.name }}
|
||||||
</mat-select>
|
</mat-option>
|
||||||
</mat-form-field>
|
</mat-select>
|
||||||
|
<mat-error *ngIf="journalEntryForm.controls.officeId.hasError('required')">
|
||||||
|
Office is <strong>required</strong>
|
||||||
|
</mat-error>
|
||||||
|
</mat-form-field>
|
||||||
|
|
||||||
<div fxFlexFill fxLayout="row wrap" fxLayout.lt-md="column" formArrayName="debits"
|
<mat-form-field fxFlex="48%">
|
||||||
*ngFor="let debit of getFormArrayData('debits').controls; let i = index;">
|
<mat-label>Currency</mat-label>
|
||||||
|
<mat-select required formControlName="currencyCode">
|
||||||
|
<mat-option *ngFor="let currency of currencyData" [value]="currency.code">
|
||||||
|
{{ currency.displayLabel }}
|
||||||
|
</mat-option>
|
||||||
|
</mat-select>
|
||||||
|
<mat-error *ngIf="journalEntryForm.controls.currencyCode.hasError('required')">
|
||||||
|
Currency is <strong>required</strong>
|
||||||
|
</mat-error>
|
||||||
|
</mat-form-field>
|
||||||
|
|
||||||
<div fxFlexFill fxLayout="row wrap" fxLayoutGap="2%" fxLayout.lt-md="column" [formGroupName]="i">
|
<div fxFlexFill fxLayout="row wrap" fxLayout.lt-md="column" formArrayName="debits"
|
||||||
|
*ngFor="let debit of debits.controls; let i = index;">
|
||||||
|
|
||||||
<mat-form-field fxFlex="48%">
|
<div fxFlexFill fxLayout="row wrap" fxLayoutGap="2%" fxLayout.lt-md="column" [formGroupName]="i">
|
||||||
<mat-select placeholder="Affected GL Entry (Debit)" required formControlName="glAccountId">
|
|
||||||
<mat-option *ngFor="let affectedGLEntryDebit of glAccountData" [value]="affectedGLEntryDebit.id">
|
|
||||||
{{ affectedGLEntryDebit.name + ' (' + affectedGLEntryDebit.glCode + ')' }}
|
|
||||||
</mat-option>
|
|
||||||
</mat-select>
|
|
||||||
</mat-form-field>
|
|
||||||
|
|
||||||
<mat-form-field fxFlex="43%">
|
<mat-form-field fxFlex="48%">
|
||||||
<input type="number" matInput placeholder="Debit Amount" required formControlName="amount">
|
<mat-label>Affected GL Entry (Debit)</mat-label>
|
||||||
</mat-form-field>
|
<mat-select required formControlName="glAccountId">
|
||||||
|
<mat-option *ngFor="let affectedGLEntryDebit of glAccountData" [value]="affectedGLEntryDebit.id">
|
||||||
|
{{ affectedGLEntryDebit.name + ' (' + affectedGLEntryDebit.glCode + ')' }}
|
||||||
|
</mat-option>
|
||||||
|
</mat-select>
|
||||||
|
<mat-error *ngIf="debits.at(i).controls.glAccountId.hasError('required')">
|
||||||
|
Affected GL Entry (Debit) is <strong>required</strong>
|
||||||
|
</mat-error>
|
||||||
|
</mat-form-field>
|
||||||
|
|
||||||
<span fxFlex>
|
<mat-form-field fxFlex="43%">
|
||||||
<button *ngIf="i !== 0" type="button" mat-icon-button (click)="removeAffectedGLEntry(journalEntryForm.get('debits'), i)"><mat-icon>remove_circle</mat-icon></button>
|
<mat-label>Debit Amount</mat-label>
|
||||||
<button *ngIf="i === 0" type="button" mat-icon-button color="primary" (click)="addAffectedGLEntry(journalEntryForm.get('debits'))"><mat-icon>add_circle</mat-icon></button>
|
<input type="number" matInput required formControlName="amount">
|
||||||
</span>
|
<mat-error *ngIf="debits.at(i).controls.amount.hasError('required')">
|
||||||
|
Debit Amount is <strong>required</strong>
|
||||||
|
</mat-error>
|
||||||
|
</mat-form-field>
|
||||||
|
|
||||||
|
<span fxFlex>
|
||||||
|
<button *ngIf="i !== 0" type="button" mat-icon-button (click)="removeAffectedGLEntry(debits, i)">
|
||||||
|
<fa-icon icon="minus-circle" size="lg"></fa-icon>
|
||||||
|
</button>
|
||||||
|
<button *ngIf="i === 0" type="button" mat-icon-button color="primary" (click)="addAffectedGLEntry(debits)">
|
||||||
|
<fa-icon icon="plus-circle" size="lg"></fa-icon>
|
||||||
|
</button>
|
||||||
|
</span>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
<div fxFlexFill fxLayout="row wrap" fxLayout.lt-md="column" formArrayName="credits"
|
||||||
|
*ngFor="let credit of credits.controls; let i = index;">
|
||||||
|
|
||||||
<div fxFlexFill fxLayout="row wrap" fxLayout.lt-md="column" formArrayName="credits"
|
<div fxFlexFill fxLayout="row wrap" fxLayoutGap="2%" fxLayout.lt-md="column" [formGroupName]="i">
|
||||||
*ngFor="let credit of getFormArrayData('credits').controls; let i = index;">
|
|
||||||
|
|
||||||
<div fxFlexFill fxLayout="row wrap" fxLayoutGap="2%" fxLayout.lt-md="column" [formGroupName]="i">
|
<mat-form-field fxFlex="48%">
|
||||||
|
<mat-label>Affected GL Entry (Credit)</mat-label>
|
||||||
|
<mat-select required formControlName="glAccountId">
|
||||||
|
<mat-option *ngFor="let affectedGLEntryCredit of glAccountData" [value]="affectedGLEntryCredit.id">
|
||||||
|
{{ affectedGLEntryCredit.name + ' (' + affectedGLEntryCredit.glCode + ')' }}
|
||||||
|
</mat-option>
|
||||||
|
</mat-select>
|
||||||
|
<mat-error *ngIf="credits.at(i).controls.glAccountId.hasError('required')">
|
||||||
|
Affected GL Entry (Credit) is <strong>required</strong>
|
||||||
|
</mat-error>
|
||||||
|
</mat-form-field>
|
||||||
|
|
||||||
<mat-form-field fxFlex="48%">
|
<mat-form-field fxFlex="43%">
|
||||||
<mat-select placeholder="Affected GL Entry (Credit)" required formControlName="glAccountId">
|
<mat-label>Credit Amount</mat-label>
|
||||||
<mat-option *ngFor="let affectedGLEntryCredit of glAccountData" [value]="affectedGLEntryCredit.id">
|
<input type="number" matInput required formControlName="amount">
|
||||||
{{ affectedGLEntryCredit.name + ' (' + affectedGLEntryCredit.glCode + ')' }}
|
<mat-error *ngIf="credits.at(i).controls.amount.hasError('required')">
|
||||||
</mat-option>
|
Credit Amount is <strong>required</strong>
|
||||||
</mat-select>
|
</mat-error>
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
|
|
||||||
<mat-form-field fxFlex="43%">
|
<span fxFlex>
|
||||||
<input type="number" matInput placeholder="Credit Amount" required formControlName="amount">
|
<button *ngIf="i !== 0" type="button" mat-icon-button (click)="removeAffectedGLEntry(credits, i)">
|
||||||
</mat-form-field>
|
<fa-icon icon="minus-circle" size="lg"></fa-icon>
|
||||||
|
</button>
|
||||||
|
<button *ngIf="i === 0" type="button" mat-icon-button color="primary" (click)="addAffectedGLEntry(credits)">
|
||||||
|
<fa-icon icon="plus-circle" size="lg"></fa-icon>
|
||||||
|
</button>
|
||||||
|
</span>
|
||||||
|
|
||||||
<span fxFlex>
|
</div>
|
||||||
<button *ngIf="i !== 0" type="button" mat-icon-button (click)="removeAffectedGLEntry(journalEntryForm.get('credits'), i)"><mat-icon>remove_circle</mat-icon></button>
|
|
||||||
<button *ngIf="i === 0 glAccountData" type="button" mat-icon-button color="primary" (click)="addAffectedGLEntry(journalEntryForm.get('credits'))"><mat-icon>add_circle</mat-icon></button>
|
|
||||||
</span>
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<mat-form-field fxFlex="48%">
|
||||||
|
<mat-label>Reference Number</mat-label>
|
||||||
|
<input matInput formControlName="referenceNumber">
|
||||||
|
</mat-form-field>
|
||||||
|
|
||||||
|
<mat-form-field fxFlex="48%">
|
||||||
|
<mat-label>Transaction Date</mat-label>
|
||||||
|
<input matInput [min]="minDate" [max]="maxDate" [matDatepicker]="transactionDatePicker" required formControlName="transactionDate">
|
||||||
|
<mat-datepicker-toggle matSuffix [for]="transactionDatePicker"></mat-datepicker-toggle>
|
||||||
|
<mat-datepicker #transactionDatePicker></mat-datepicker>
|
||||||
|
<mat-error *ngIf="journalEntryForm.controls.transactionDate.hasError('required')">
|
||||||
|
Transaction Date is <strong>required</strong>
|
||||||
|
</mat-error>
|
||||||
|
</mat-form-field>
|
||||||
|
|
||||||
|
<mat-form-field fxFlex="48%">
|
||||||
|
<mat-label>Payment Type</mat-label>
|
||||||
|
<mat-select formControlName="paymentTypeId">
|
||||||
|
<mat-option *ngFor="let paymentType of paymentTypeData" [value]="paymentType.id">
|
||||||
|
{{ paymentType.name }}
|
||||||
|
</mat-option>
|
||||||
|
</mat-select>
|
||||||
|
</mat-form-field>
|
||||||
|
|
||||||
|
<mat-form-field fxFlex="48%">
|
||||||
|
<mat-label>Account Number</mat-label>
|
||||||
|
<input matInput formControlName="accountNumber">
|
||||||
|
</mat-form-field>
|
||||||
|
|
||||||
|
<mat-form-field fxFlex="48%">
|
||||||
|
<mat-label>Cheque Number</mat-label>
|
||||||
|
<input matInput formControlName="checkNumber">
|
||||||
|
</mat-form-field>
|
||||||
|
|
||||||
|
<mat-form-field fxFlex="48%">
|
||||||
|
<mat-label>Routing Code</mat-label>
|
||||||
|
<input matInput formControlName="routingCode">
|
||||||
|
</mat-form-field>
|
||||||
|
|
||||||
|
<mat-form-field fxFlex="48%">
|
||||||
|
<mat-label>Receipt Number</mat-label>
|
||||||
|
<input matInput formControlName="receiptNumber">
|
||||||
|
</mat-form-field>
|
||||||
|
|
||||||
|
<mat-form-field fxFlex="48%">
|
||||||
|
<mat-label>Bank Number</mat-label>
|
||||||
|
<input matInput formControlName="bankNumber">
|
||||||
|
</mat-form-field>
|
||||||
|
|
||||||
|
<mat-form-field fxFlex="98%">
|
||||||
|
<mat-label>Comments</mat-label>
|
||||||
|
<textarea matInput formControlName="comments"></textarea>
|
||||||
|
</mat-form-field>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<mat-form-field fxFlex="48%">
|
</mat-card-content>
|
||||||
<input matInput placeholder="Reference Number" formControlName="referenceNumber">
|
|
||||||
</mat-form-field>
|
|
||||||
|
|
||||||
<mat-form-field fxFlex="48%">
|
<mat-card-actions fxLayout="row" fxLayout.xs="column" fxLayoutAlign="center" fxLayoutGap="5px">
|
||||||
<input matInput [min]="minDate" [max]="maxDate" [matDatepicker]="transactionDatePicker" placeholder="Transaction Date" required formControlName="transactionDate">
|
<button type="button" mat-raised-button [routerLink]="['../']">Cancel</button>
|
||||||
<mat-datepicker-toggle matSuffix [for]="transactionDatePicker"></mat-datepicker-toggle>
|
<button mat-raised-button color="primary" [disabled]="!journalEntryForm.valid">Submit</button>
|
||||||
<mat-datepicker #transactionDatePicker></mat-datepicker>
|
</mat-card-actions>
|
||||||
</mat-form-field>
|
|
||||||
|
|
||||||
<mat-form-field fxFlex="48%">
|
</form>
|
||||||
<mat-select placeholder="Payment Type" formControlName="paymentTypeId">
|
|
||||||
<mat-option *ngFor="let paymentType of paymentTypeData" [value]="paymentType.id">
|
|
||||||
{{ paymentType.name }}
|
|
||||||
</mat-option>
|
|
||||||
</mat-select>
|
|
||||||
</mat-form-field>
|
|
||||||
|
|
||||||
<mat-form-field fxFlex="48%">
|
</mat-card>
|
||||||
<input matInput placeholder="Account Number" formControlName="accountNumber">
|
|
||||||
</mat-form-field>
|
|
||||||
|
|
||||||
<mat-form-field fxFlex="48%">
|
|
||||||
<input matInput placeholder="Cheque Number" formControlName="checkNumber">
|
|
||||||
</mat-form-field>
|
|
||||||
|
|
||||||
<mat-form-field fxFlex="48%">
|
|
||||||
<input matInput placeholder="Routing Code" formControlName="routingCode">
|
|
||||||
</mat-form-field>
|
|
||||||
|
|
||||||
<mat-form-field fxFlex="48%">
|
|
||||||
<input matInput placeholder="Receipt Number" formControlName="receiptNumber">
|
|
||||||
</mat-form-field>
|
|
||||||
|
|
||||||
<mat-form-field fxFlex="48%">
|
|
||||||
<input matInput placeholder="Bank Number" formControlName="bankNumber">
|
|
||||||
</mat-form-field>
|
|
||||||
|
|
||||||
<mat-form-field fxFlex="98%">
|
|
||||||
<textarea matInput placeholder="Comments" formControlName="comments"></textarea>
|
|
||||||
</mat-form-field>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</mat-card-content>
|
|
||||||
|
|
||||||
<mat-card-actions fxLayout="row" fxLayout.xs="column" fxLayoutAlign="center" fxLayoutGap="5px">
|
|
||||||
<button type="button" mat-raised-button [routerLink]="['/accounting']">Cancel</button>
|
|
||||||
<button mat-raised-button color="primary">Submit</button>
|
|
||||||
</mat-card-actions>
|
|
||||||
|
|
||||||
</form>
|
|
||||||
|
|
||||||
</mat-card>
|
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|||||||
@@ -1,9 +1,14 @@
|
|||||||
|
/** Angular Imports */
|
||||||
import { Component, OnInit } from '@angular/core';
|
import { Component, OnInit } from '@angular/core';
|
||||||
import { FormGroup, FormBuilder, Validators, FormArray } from '@angular/forms';
|
import { FormGroup, FormBuilder, Validators, FormArray } from '@angular/forms';
|
||||||
import { Router } from '@angular/router';
|
import { Router, ActivatedRoute } from '@angular/router';
|
||||||
|
|
||||||
|
/** Custom Services */
|
||||||
import { AccountingService } from '../accounting.service';
|
import { AccountingService } from '../accounting.service';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create Journal Entry component.
|
||||||
|
*/
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'mifosx-create-journal-entry',
|
selector: 'mifosx-create-journal-entry',
|
||||||
templateUrl: './create-journal-entry.component.html',
|
templateUrl: './create-journal-entry.component.html',
|
||||||
@@ -11,28 +16,55 @@ import { AccountingService } from '../accounting.service';
|
|||||||
})
|
})
|
||||||
export class CreateJournalEntryComponent implements OnInit {
|
export class CreateJournalEntryComponent implements OnInit {
|
||||||
|
|
||||||
// TODO: Validations
|
/** Minimum transaction date allowed. */
|
||||||
|
|
||||||
minDate = new Date(2000, 0, 1);
|
minDate = new Date(2000, 0, 1);
|
||||||
|
/** Maximum transaction date allowed. */
|
||||||
maxDate = new Date();
|
maxDate = new Date();
|
||||||
|
/** Journal entry form. */
|
||||||
journalEntryForm: FormGroup;
|
journalEntryForm: FormGroup;
|
||||||
|
/** Office data. */
|
||||||
officeData: any;
|
officeData: any;
|
||||||
|
/** Currency data. */
|
||||||
currencyData: any;
|
currencyData: any;
|
||||||
|
/** Payment type data. */
|
||||||
paymentTypeData: any;
|
paymentTypeData: any;
|
||||||
|
/** Gl Account data. */
|
||||||
glAccountData: any;
|
glAccountData: any;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the offices, currencies, payment types and gl accounts data from `resolve`.
|
||||||
|
* @param {FormBuilder} formBuilder Form Builder.
|
||||||
|
* @param {AccountingService} accountingService Accounting Service.
|
||||||
|
* @param {ActivatedRoute} route Activated Route.
|
||||||
|
* @param {Router} router Router for navigation.
|
||||||
|
*/
|
||||||
constructor(private formBuilder: FormBuilder,
|
constructor(private formBuilder: FormBuilder,
|
||||||
private accountingService: AccountingService,
|
private accountingService: AccountingService,
|
||||||
private router: Router) { }
|
private route: ActivatedRoute,
|
||||||
|
private router: Router) {
|
||||||
ngOnInit() {
|
this.route.data.subscribe((data: {
|
||||||
this.createJournalEntryForm();
|
offices: any,
|
||||||
this.getOffices();
|
currencies: any,
|
||||||
this.getCurrencies();
|
paymentTypes: any,
|
||||||
this.getPaymentTypes();
|
glAccounts: any
|
||||||
this.getGlAccounts();
|
}) => {
|
||||||
|
this.officeData = data.offices;
|
||||||
|
this.currencyData = data.currencies.selectedCurrencyOptions;
|
||||||
|
this.paymentTypeData = data.paymentTypes;
|
||||||
|
this.glAccountData = data.glAccounts;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates the journal entry form.
|
||||||
|
*/
|
||||||
|
ngOnInit() {
|
||||||
|
this.createJournalEntryForm();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates the journal entry form.
|
||||||
|
*/
|
||||||
createJournalEntryForm() {
|
createJournalEntryForm() {
|
||||||
this.journalEntryForm = this.formBuilder.group({
|
this.journalEntryForm = this.formBuilder.group({
|
||||||
'officeId': ['', Validators.required],
|
'officeId': ['', Validators.required],
|
||||||
@@ -51,6 +83,10 @@ export class CreateJournalEntryComponent implements OnInit {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates the affected gl entry form.
|
||||||
|
* @returns {FormGroup} Affected gl entry form.
|
||||||
|
*/
|
||||||
createAffectedGLEntryForm(): FormGroup {
|
createAffectedGLEntryForm(): FormGroup {
|
||||||
return this.formBuilder.group({
|
return this.formBuilder.group({
|
||||||
'glAccountId': ['', Validators.required],
|
'glAccountId': ['', Validators.required],
|
||||||
@@ -58,50 +94,62 @@ export class CreateJournalEntryComponent implements OnInit {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
getFormArrayData(type: string): FormArray {
|
/**
|
||||||
return <FormArray>this.journalEntryForm.get(type);
|
* Gets the affected gl entry (debits) form array.
|
||||||
|
* @returns {FormArray} Debits form array.
|
||||||
|
*/
|
||||||
|
get debits(): FormArray {
|
||||||
|
return this.journalEntryForm.get('debits') as FormArray;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the affected gl entry (credits) form array.
|
||||||
|
* @returns {FormArray} Credits form array.
|
||||||
|
*/
|
||||||
|
get credits(): FormArray {
|
||||||
|
return this.journalEntryForm.get('credits') as FormArray;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds the affected gl entry form to given affected gl entry form array.
|
||||||
|
* @param {FormArray} affectedGLEntryFormArray Given affected gl entry form array (debit/credit).
|
||||||
|
*/
|
||||||
addAffectedGLEntry(affectedGLEntryFormArray: FormArray) {
|
addAffectedGLEntry(affectedGLEntryFormArray: FormArray) {
|
||||||
affectedGLEntryFormArray.push(this.createAffectedGLEntryForm());
|
affectedGLEntryFormArray.push(this.createAffectedGLEntryForm());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes the affected gl entry form from given affected gl entry form array at given index.
|
||||||
|
* @param {FormArray} affectedGLEntryFormArray Given affected gl entry form array (debit/credit).
|
||||||
|
* @param {number} index Array index from where affected gl entry form needs to be removed.
|
||||||
|
*/
|
||||||
removeAffectedGLEntry(affectedGLEntryFormArray: FormArray, index: number) {
|
removeAffectedGLEntry(affectedGLEntryFormArray: FormArray, index: number) {
|
||||||
affectedGLEntryFormArray.removeAt(index);
|
affectedGLEntryFormArray.removeAt(index);
|
||||||
}
|
}
|
||||||
|
|
||||||
getOffices() {
|
/**
|
||||||
this.accountingService.getOffices().subscribe(officeData => {
|
* Submits the journal entries form and creates journal entry,
|
||||||
this.officeData = officeData;
|
* if successful redirects to view created transaction.
|
||||||
});
|
*/
|
||||||
}
|
|
||||||
|
|
||||||
getCurrencies() {
|
|
||||||
this.accountingService.getCurrencies().subscribe(currencyData => {
|
|
||||||
this.currencyData = currencyData.selectedCurrencyOptions;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
getPaymentTypes() {
|
|
||||||
this.accountingService.getPaymentTypes().subscribe(paymentTypeData => {
|
|
||||||
this.paymentTypeData = paymentTypeData;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
getGlAccounts() {
|
|
||||||
this.accountingService.getGlAccounts().subscribe(glAccountData => {
|
|
||||||
this.glAccountData = glAccountData;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
submit() {
|
submit() {
|
||||||
const journalEntry = this.journalEntryForm.value;
|
const journalEntry = this.journalEntryForm.value;
|
||||||
// TODO: Update once language and date settings are setup
|
// TODO: Update once language and date settings are setup
|
||||||
journalEntry.locale = 'en';
|
journalEntry.locale = 'en';
|
||||||
journalEntry.dateFormat = 'dd MMMM yyyy';
|
journalEntry.dateFormat = 'yyyy-MM-dd';
|
||||||
journalEntry.transactionDate = '20 July 2018';
|
if (journalEntry.transactionDate instanceof Date) {
|
||||||
|
let day = journalEntry.transactionDate.getDate();
|
||||||
|
let month = journalEntry.transactionDate.getMonth() + 1;
|
||||||
|
const year = journalEntry.transactionDate.getFullYear();
|
||||||
|
if (day < 10) {
|
||||||
|
day = `0${day}`;
|
||||||
|
}
|
||||||
|
if (month < 10) {
|
||||||
|
month = `0${month}`;
|
||||||
|
}
|
||||||
|
journalEntry.transactionDate = `${year}-${month}-${day}`;
|
||||||
|
}
|
||||||
this.accountingService.createJournalEntry(journalEntry).subscribe(response => {
|
this.accountingService.createJournalEntry(journalEntry).subscribe(response => {
|
||||||
this.router.navigate(['/accounting/transactions/view', response.transactionId]);
|
this.router.navigate(['../transactions/view', response.transactionId], { relativeTo: this.route });
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+13
-5
@@ -1,7 +1,7 @@
|
|||||||
<div class="container">
|
<div class="container">
|
||||||
|
|
||||||
<mat-card>
|
<mat-card>
|
||||||
|
|
||||||
<form [formGroup]="financialActivityMappingForm" (ngSubmit)="submit()">
|
<form [formGroup]="financialActivityMappingForm" (ngSubmit)="submit()">
|
||||||
|
|
||||||
<mat-card-content>
|
<mat-card-content>
|
||||||
@@ -9,19 +9,27 @@
|
|||||||
<div fxLayout="column">
|
<div fxLayout="column">
|
||||||
|
|
||||||
<mat-form-field>
|
<mat-form-field>
|
||||||
<mat-select placeholder="Financial Activity" required formControlName="financialActivityId">
|
<mat-label>Financial Activity</mat-label>
|
||||||
|
<mat-select required formControlName="financialActivityId">
|
||||||
<mat-option *ngFor="let financialActivity of financialActivityData" [value]="financialActivity.id">
|
<mat-option *ngFor="let financialActivity of financialActivityData" [value]="financialActivity.id">
|
||||||
{{ financialActivity.name }}
|
{{ financialActivity.name }}
|
||||||
</mat-option>
|
</mat-option>
|
||||||
</mat-select>
|
</mat-select>
|
||||||
|
<mat-error *ngIf="financialActivityMappingForm.controls.financialActivityId.hasError('required')">
|
||||||
|
Financial Activity is <strong>required</strong>
|
||||||
|
</mat-error>
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
|
|
||||||
<mat-form-field>
|
<mat-form-field>
|
||||||
<mat-select placeholder="Account" required formControlName="glAccountId">
|
<mat-label>Account</mat-label>
|
||||||
|
<mat-select required formControlName="glAccountId">
|
||||||
<mat-option *ngFor="let glAccount of glAccountData" [value]="glAccount.id">
|
<mat-option *ngFor="let glAccount of glAccountData" [value]="glAccount.id">
|
||||||
{{ glAccount.name + ' (' + glAccount.glCode + ')' }}
|
{{ glAccount.name + ' (' + glAccount.glCode + ')' }}
|
||||||
</mat-option>
|
</mat-option>
|
||||||
</mat-select>
|
</mat-select>
|
||||||
|
<mat-error *ngIf="financialActivityMappingForm.controls.glAccountId.hasError('required')">
|
||||||
|
Account is <strong>required</strong>
|
||||||
|
</mat-error>
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
@@ -29,8 +37,8 @@
|
|||||||
</mat-card-content>
|
</mat-card-content>
|
||||||
|
|
||||||
<mat-card-actions fxLayout="row" fxLayout.xs="column" fxLayoutAlign="center" fxLayoutGap="5px">
|
<mat-card-actions fxLayout="row" fxLayout.xs="column" fxLayoutAlign="center" fxLayoutGap="5px">
|
||||||
<button type="button" mat-raised-button [routerLink]="['/accounting/financial-activity-mappings']">Cancel</button>
|
<button type="button" mat-raised-button [routerLink]="['../']">Cancel</button>
|
||||||
<button mat-raised-button color="primary">Submit</button>
|
<button mat-raised-button color="primary" [disabled]="!financialActivityMappingForm.valid">Submit</button>
|
||||||
</mat-card-actions>
|
</mat-card-actions>
|
||||||
|
|
||||||
</form>
|
</form>
|
||||||
|
|||||||
+60
-32
@@ -1,9 +1,14 @@
|
|||||||
|
/** Angular Imports */
|
||||||
import { Component, OnInit } from '@angular/core';
|
import { Component, OnInit } from '@angular/core';
|
||||||
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
|
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
|
||||||
import { Router } from '@angular/router';
|
import { Router, ActivatedRoute } from '@angular/router';
|
||||||
|
|
||||||
|
/** Custom Services */
|
||||||
import { AccountingService } from '../../accounting.service';
|
import { AccountingService } from '../../accounting.service';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create financial activity mapping component.
|
||||||
|
*/
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'mifosx-create-financial-activity-mapping',
|
selector: 'mifosx-create-financial-activity-mapping',
|
||||||
templateUrl: './create-financial-activity-mapping.component.html',
|
templateUrl: './create-financial-activity-mapping.component.html',
|
||||||
@@ -11,56 +16,79 @@ import { AccountingService } from '../../accounting.service';
|
|||||||
})
|
})
|
||||||
export class CreateFinancialActivityMappingComponent implements OnInit {
|
export class CreateFinancialActivityMappingComponent implements OnInit {
|
||||||
|
|
||||||
|
/** Financial activity mapping form. */
|
||||||
financialActivityMappingForm: FormGroup;
|
financialActivityMappingForm: FormGroup;
|
||||||
|
/** GL Account options. */
|
||||||
glAccountOptions: any;
|
glAccountOptions: any;
|
||||||
|
/** GL Account data. */
|
||||||
glAccountData: any;
|
glAccountData: any;
|
||||||
|
/** Financial activity data. */
|
||||||
financialActivityData: any;
|
financialActivityData: any;
|
||||||
|
|
||||||
constructor(private formBuider: FormBuilder,
|
/**
|
||||||
|
* Retrieves the gl account options and financial activity data from `resolve`.
|
||||||
|
* @param {FormBuilder} formBuilder Form Builder.
|
||||||
|
* @param {AccountingService} accountingService Accounting Service.
|
||||||
|
* @param {ActivatedRoute} route Activated Route.
|
||||||
|
* @param {Router} router Router for navigation.
|
||||||
|
*/
|
||||||
|
constructor(private formBuilder: FormBuilder,
|
||||||
private accountingService: AccountingService,
|
private accountingService: AccountingService,
|
||||||
private router: Router) { }
|
private route: ActivatedRoute,
|
||||||
|
private router: Router) {
|
||||||
ngOnInit() {
|
this.route.data.subscribe((data: { financialActivityAccountsTemplate: any }) => {
|
||||||
this.createFinancialActivityMappingForm();
|
this.glAccountOptions = data.financialActivityAccountsTemplate.glAccountOptions;
|
||||||
this.getFinancialActivityAccountsTemplate();
|
this.financialActivityData = data.financialActivityAccountsTemplate.financialActivityOptions;
|
||||||
this.setGLAccountData();
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates the financial activity mapping form and sets the gl account data.
|
||||||
|
*/
|
||||||
|
ngOnInit() {
|
||||||
|
this.createFinancialActivityMappingForm();
|
||||||
|
this.setGlAccountData();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates the financial activity mapping form.
|
||||||
|
*/
|
||||||
createFinancialActivityMappingForm() {
|
createFinancialActivityMappingForm() {
|
||||||
this.financialActivityMappingForm = this.formBuider.group({
|
this.financialActivityMappingForm = this.formBuilder.group({
|
||||||
'financialActivityId': ['', Validators.required],
|
'financialActivityId': ['', Validators.required],
|
||||||
'glAccountId': ['', Validators.required]
|
'glAccountId': ['', Validators.required]
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
getFinancialActivityAccountsTemplate() {
|
/**
|
||||||
this.accountingService.getFinancialActivityAccountsTemplate().subscribe((financialActivityAccountData: any) => {
|
* Sets the gl account data on the basis of selected financial activity.
|
||||||
this.glAccountOptions = financialActivityAccountData.glAccountOptions;
|
*/
|
||||||
this.financialActivityData = financialActivityAccountData.financialActivityOptions;
|
setGlAccountData() {
|
||||||
});
|
this.financialActivityMappingForm.get('financialActivityId').valueChanges
|
||||||
}
|
.subscribe(financialActivityId => {
|
||||||
|
switch (financialActivityId) {
|
||||||
setGLAccountData() {
|
case 100:
|
||||||
this.financialActivityMappingForm.get('financialActivityId').valueChanges.subscribe(financialActivityId => {
|
case 101:
|
||||||
switch (financialActivityId) {
|
case 102:
|
||||||
case 100:
|
case 103: this.glAccountData = this.glAccountOptions.assetAccountOptions;
|
||||||
case 101:
|
break;
|
||||||
case 102:
|
case 200:
|
||||||
case 103: this.glAccountData = this.glAccountOptions.assetAccountOptions;
|
case 201: this.glAccountData = this.glAccountOptions.liabilityAccountOptions;
|
||||||
break;
|
break;
|
||||||
case 200:
|
case 300: this.glAccountData = this.glAccountOptions.equityAccountOptions;
|
||||||
case 201: this.glAccountData = this.glAccountOptions.liabilityAccountOptions;
|
break;
|
||||||
break;
|
}
|
||||||
case 300: this.glAccountData = this.glAccountOptions.equityAccountOptions;
|
});
|
||||||
break;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Submits the financial activity mapping form and creates financial activity account,
|
||||||
|
* if successful redirects to view created account.
|
||||||
|
*/
|
||||||
submit() {
|
submit() {
|
||||||
this.accountingService.createFinancialActivityAccount(this.financialActivityMappingForm.value)
|
this.accountingService.createFinancialActivityAccount(this.financialActivityMappingForm.value)
|
||||||
.subscribe((response: any) => {
|
.subscribe((response: any) => {
|
||||||
this.router.navigate(['/accounting/financial-activity-mappings/view', response.resourceId]);
|
this.router.navigate(['../view', response.resourceId], { relativeTo: this.route });
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+30
@@ -0,0 +1,30 @@
|
|||||||
|
/** Angular Imports */
|
||||||
|
import { Injectable } from '@angular/core';
|
||||||
|
import { Resolve } from '@angular/router';
|
||||||
|
|
||||||
|
/** rxjs Imports */
|
||||||
|
import { Observable } from 'rxjs';
|
||||||
|
|
||||||
|
/** Custom Services */
|
||||||
|
import { AccountingService } from '../../accounting.service';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Financial activity mappings template data resolver.
|
||||||
|
*/
|
||||||
|
@Injectable()
|
||||||
|
export class FinancialActivityMappingsTemplateResolver implements Resolve<Object> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {AccountingService} accountingService Accounting service.
|
||||||
|
*/
|
||||||
|
constructor(private accountingService: AccountingService) {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the financial activity mappings template data.
|
||||||
|
* @returns {Observable<any>}
|
||||||
|
*/
|
||||||
|
resolve(): Observable<any> {
|
||||||
|
return this.accountingService.getFinancialActivityAccountsTemplate();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+6
-4
@@ -9,7 +9,8 @@
|
|||||||
<div fxLayout="column">
|
<div fxLayout="column">
|
||||||
|
|
||||||
<mat-form-field>
|
<mat-form-field>
|
||||||
<mat-select placeholder="Financial Activity" required formControlName="financialActivityId">
|
<mat-label>Financial Activity</mat-label>
|
||||||
|
<mat-select required formControlName="financialActivityId">
|
||||||
<mat-option *ngFor="let financialActivity of financialActivityData" [value]="financialActivity.id">
|
<mat-option *ngFor="let financialActivity of financialActivityData" [value]="financialActivity.id">
|
||||||
{{ financialActivity.name }}
|
{{ financialActivity.name }}
|
||||||
</mat-option>
|
</mat-option>
|
||||||
@@ -17,7 +18,8 @@
|
|||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
|
|
||||||
<mat-form-field>
|
<mat-form-field>
|
||||||
<mat-select placeholder="Account" required formControlName="glAccountId">
|
<mat-label>Account</mat-label>
|
||||||
|
<mat-select required formControlName="glAccountId">
|
||||||
<mat-option *ngFor="let glAccount of glAccountData" [value]="glAccount.id">
|
<mat-option *ngFor="let glAccount of glAccountData" [value]="glAccount.id">
|
||||||
{{ glAccount.name + ' (' + glAccount.glCode + ')' }}
|
{{ glAccount.name + ' (' + glAccount.glCode + ')' }}
|
||||||
</mat-option>
|
</mat-option>
|
||||||
@@ -29,8 +31,8 @@
|
|||||||
</mat-card-content>
|
</mat-card-content>
|
||||||
|
|
||||||
<mat-card-actions fxLayout="row" fxLayout.xs="column" fxLayoutAlign="center" fxLayoutGap="5px">
|
<mat-card-actions fxLayout="row" fxLayout.xs="column" fxLayoutAlign="center" fxLayoutGap="5px">
|
||||||
<button type="button" mat-raised-button [routerLink]="['/accounting/financial-activity-mappings/view', financialActivityAccountId]">Cancel</button>
|
<button type="button" mat-raised-button [routerLink]="['../']">Cancel</button>
|
||||||
<button mat-raised-button color="primary">Submit</button>
|
<button mat-raised-button color="primary" [disabled]="financialActivityMappingForm.pristine">Submit</button>
|
||||||
</mat-card-actions>
|
</mat-card-actions>
|
||||||
|
|
||||||
</form>
|
</form>
|
||||||
|
|||||||
+68
-35
@@ -1,9 +1,14 @@
|
|||||||
|
/** Angular Imports */
|
||||||
import { Component, OnInit } from '@angular/core';
|
import { Component, OnInit } from '@angular/core';
|
||||||
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
|
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
|
||||||
import { Router, ActivatedRoute } from '@angular/router';
|
import { Router, ActivatedRoute } from '@angular/router';
|
||||||
|
|
||||||
|
/** Custom Services */
|
||||||
import { AccountingService } from '../../accounting.service';
|
import { AccountingService } from '../../accounting.service';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Edit financial activity mapping component.
|
||||||
|
*/
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'mifosx-edit-financial-activity-mapping',
|
selector: 'mifosx-edit-financial-activity-mapping',
|
||||||
templateUrl: './edit-financial-activity-mapping.component.html',
|
templateUrl: './edit-financial-activity-mapping.component.html',
|
||||||
@@ -11,24 +16,54 @@ import { AccountingService } from '../../accounting.service';
|
|||||||
})
|
})
|
||||||
export class EditFinancialActivityMappingComponent implements OnInit {
|
export class EditFinancialActivityMappingComponent implements OnInit {
|
||||||
|
|
||||||
|
/** Financial activity mapping form. */
|
||||||
financialActivityMappingForm: FormGroup;
|
financialActivityMappingForm: FormGroup;
|
||||||
|
/** GL Account options. */
|
||||||
glAccountOptions: any;
|
glAccountOptions: any;
|
||||||
|
/** GL Account data. */
|
||||||
glAccountData: any;
|
glAccountData: any;
|
||||||
financialActivityAccountId: any;
|
/** Financial activity data. */
|
||||||
financialActivityData: any;
|
financialActivityData: any;
|
||||||
|
/** Financial activity account ID. */
|
||||||
|
financialActivityAccountId: string;
|
||||||
|
/** Financial activity ID. */
|
||||||
|
financialActivityId: number;
|
||||||
|
/** GL Account ID. */
|
||||||
|
glAccountId: number;
|
||||||
|
|
||||||
constructor(private route: ActivatedRoute,
|
/**
|
||||||
private formBuider: FormBuilder,
|
* Retrieves the gl account options, financial activity and financial activity account data from `resolve`.
|
||||||
|
* @param {FormBuilder} formBuilder Form Builder.
|
||||||
|
* @param {AccountingService} accountingService Accounting Service.
|
||||||
|
* @param {ActivatedRoute} route Activated Route.
|
||||||
|
* @param {Router} router Router for navigation.
|
||||||
|
*/
|
||||||
|
constructor(private formBuider: FormBuilder,
|
||||||
private accountingService: AccountingService,
|
private accountingService: AccountingService,
|
||||||
private router: Router) { }
|
private route: ActivatedRoute,
|
||||||
|
private router: Router) {
|
||||||
ngOnInit() {
|
this.route.data.subscribe((data: { financialActivityAccountAndTemplate: any }) => {
|
||||||
this.financialActivityAccountId = this.route.snapshot.paramMap.get('id');
|
this.financialActivityAccountId = data.financialActivityAccountAndTemplate.id;
|
||||||
this.createFinancialActivityMappingForm();
|
this.financialActivityId = data.financialActivityAccountAndTemplate.financialActivityData.id;
|
||||||
this.setGLAccountData();
|
this.glAccountId = data.financialActivityAccountAndTemplate.glAccountData.id;
|
||||||
this.getFinancialActivityAccount();
|
this.glAccountOptions = data.financialActivityAccountAndTemplate.glAccountOptions;
|
||||||
|
this.financialActivityData = data.financialActivityAccountAndTemplate.financialActivityOptions;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates and sets the financial activity mapping form and sets the gl account data.
|
||||||
|
*/
|
||||||
|
ngOnInit() {
|
||||||
|
this.createFinancialActivityMappingForm();
|
||||||
|
this.setGLAccountData();
|
||||||
|
this.financialActivityMappingForm.get('financialActivityId').setValue(this.financialActivityId);
|
||||||
|
this.financialActivityMappingForm.get('glAccountId').setValue(this.glAccountId);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates the financial activity mapping form.
|
||||||
|
*/
|
||||||
createFinancialActivityMappingForm() {
|
createFinancialActivityMappingForm() {
|
||||||
this.financialActivityMappingForm = this.formBuider.group({
|
this.financialActivityMappingForm = this.formBuider.group({
|
||||||
'financialActivityId': ['', Validators.required],
|
'financialActivityId': ['', Validators.required],
|
||||||
@@ -36,37 +71,35 @@ export class EditFinancialActivityMappingComponent implements OnInit {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
getFinancialActivityAccount() {
|
/**
|
||||||
this.accountingService.getFinancialActivityAccount(this.financialActivityAccountId, true)
|
* Sets the gl account data on the basis of selected financial activity.
|
||||||
.subscribe((financialActivityAccountData: any) => {
|
*/
|
||||||
this.glAccountOptions = financialActivityAccountData.glAccountOptions;
|
setGLAccountData() {
|
||||||
this.financialActivityData = financialActivityAccountData.financialActivityOptions;
|
this.financialActivityMappingForm.get('financialActivityId').valueChanges
|
||||||
this.financialActivityMappingForm.get('financialActivityId').setValue(financialActivityAccountData.financialActivityData.id);
|
.subscribe(financialActivityId => {
|
||||||
this.financialActivityMappingForm.get('glAccountId').setValue(financialActivityAccountData.glAccountData.id);
|
switch (financialActivityId) {
|
||||||
|
case 100:
|
||||||
|
case 101:
|
||||||
|
case 102:
|
||||||
|
case 103: this.glAccountData = this.glAccountOptions.assetAccountOptions;
|
||||||
|
break;
|
||||||
|
case 200:
|
||||||
|
case 201: this.glAccountData = this.glAccountOptions.liabilityAccountOptions;
|
||||||
|
break;
|
||||||
|
case 300: this.glAccountData = this.glAccountOptions.equityAccountOptions;
|
||||||
|
break;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
setGLAccountData() {
|
/**
|
||||||
this.financialActivityMappingForm.get('financialActivityId').valueChanges.subscribe(financialActivityId => {
|
* Submits the financial activity mapping form and updates financial activity account,
|
||||||
switch (financialActivityId) {
|
* if successful redirects to view updated account.
|
||||||
case 100:
|
*/
|
||||||
case 101:
|
|
||||||
case 102:
|
|
||||||
case 103: this.glAccountData = this.glAccountOptions.assetAccountOptions;
|
|
||||||
break;
|
|
||||||
case 200:
|
|
||||||
case 201: this.glAccountData = this.glAccountOptions.liabilityAccountOptions;
|
|
||||||
break;
|
|
||||||
case 300: this.glAccountData = this.glAccountOptions.equityAccountOptions;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
submit() {
|
submit() {
|
||||||
this.accountingService.updateFinancialActivityAccount(this.financialActivityAccountId, this.financialActivityMappingForm.value)
|
this.accountingService.updateFinancialActivityAccount(this.financialActivityAccountId, this.financialActivityMappingForm.value)
|
||||||
.subscribe((response: any) => {
|
.subscribe((response: any) => {
|
||||||
this.router.navigate(['/accounting/financial-activity-mappings/view', response.resourceId]);
|
this.router.navigate(['../../', response.resourceId], { relativeTo: this.route });
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+31
@@ -0,0 +1,31 @@
|
|||||||
|
/** Angular Imports */
|
||||||
|
import { Injectable } from '@angular/core';
|
||||||
|
import { Resolve, ActivatedRouteSnapshot } from '@angular/router';
|
||||||
|
|
||||||
|
/** rxjs Imports */
|
||||||
|
import { Observable } from 'rxjs';
|
||||||
|
|
||||||
|
/** Custom Services */
|
||||||
|
import { AccountingService } from '../../accounting.service';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Financial activity mapping and template data resolver.
|
||||||
|
*/
|
||||||
|
@Injectable()
|
||||||
|
export class FinancialActivityMappingAndTemplateResolver implements Resolve<Object> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {AccountingService} accountingService Accounting service.
|
||||||
|
*/
|
||||||
|
constructor(private accountingService: AccountingService) {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the financial activity mapping and template data.
|
||||||
|
* @returns {Observable<any>}
|
||||||
|
*/
|
||||||
|
resolve(route: ActivatedRouteSnapshot): Observable<any> {
|
||||||
|
const financialActivityAccountId = route.paramMap.get('id');
|
||||||
|
return this.accountingService.getFinancialActivityAccount(financialActivityAccountId, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+3
-3
@@ -1,6 +1,6 @@
|
|||||||
<div fxLayout="row" fxLayoutAlign="end" class="container m-b-20">
|
<div fxLayout="row" fxLayoutAlign="end" class="container m-b-20">
|
||||||
<button mat-raised-button color="primary" [routerLink]="['/accounting/financial-activity-mappings/create']">
|
<button mat-raised-button color="primary" [routerLink]="['create']">
|
||||||
<mat-icon>add</mat-icon> Define New Mapping
|
<fa-icon icon="plus"></fa-icon> Define New Mapping
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -24,7 +24,7 @@
|
|||||||
</ng-container>
|
</ng-container>
|
||||||
|
|
||||||
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
|
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
|
||||||
<tr mat-row *matRowDef="let row; columns: displayedColumns;" [routerLink]="['/accounting/financial-activity-mappings/view', row.id]"></tr>
|
<tr mat-row *matRowDef="let row; columns: displayedColumns;" [routerLink]="['view', row.id]" class="select-row"></tr>
|
||||||
|
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
|
|||||||
+4
@@ -1,3 +1,7 @@
|
|||||||
table {
|
table {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
|
||||||
|
.select-row:hover {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+43
-22
@@ -1,8 +1,11 @@
|
|||||||
|
/** Angular Imports */
|
||||||
import { Component, OnInit, ViewChild } from '@angular/core';
|
import { Component, OnInit, ViewChild } from '@angular/core';
|
||||||
import { MatTableDataSource, MatPaginator, MatSort } from '@angular/material';
|
import { MatTableDataSource, MatPaginator, MatSort } from '@angular/material';
|
||||||
|
import { ActivatedRoute } from '@angular/router';
|
||||||
|
|
||||||
import { AccountingService } from '../accounting.service';
|
/**
|
||||||
|
* Financial activity mappings component.
|
||||||
|
*/
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'mifosx-financial-activity-mappings',
|
selector: 'mifosx-financial-activity-mappings',
|
||||||
templateUrl: './financial-activity-mappings.component.html',
|
templateUrl: './financial-activity-mappings.component.html',
|
||||||
@@ -10,32 +13,50 @@ import { AccountingService } from '../accounting.service';
|
|||||||
})
|
})
|
||||||
export class FinancialActivityMappingsComponent implements OnInit {
|
export class FinancialActivityMappingsComponent implements OnInit {
|
||||||
|
|
||||||
|
/** Financial activity account data. */
|
||||||
|
financialActivityAccountData: any;
|
||||||
|
/** Columns to be displayed in financial activity mappings table. */
|
||||||
displayedColumns: string[] = ['financialActivity', 'glAccountName', 'glAccountCode'];
|
displayedColumns: string[] = ['financialActivity', 'glAccountName', 'glAccountCode'];
|
||||||
dataSource: any;
|
/** Data source for financial activity mappings table. */
|
||||||
|
dataSource: MatTableDataSource<any>;
|
||||||
|
|
||||||
|
/** Paginator for financial activity mappings table. */
|
||||||
@ViewChild(MatPaginator) paginator: MatPaginator;
|
@ViewChild(MatPaginator) paginator: MatPaginator;
|
||||||
|
/** Sorter for financial activity mappings table. */
|
||||||
@ViewChild(MatSort) sort: MatSort;
|
@ViewChild(MatSort) sort: MatSort;
|
||||||
|
|
||||||
constructor(private accountingService: AccountingService) { }
|
/**
|
||||||
|
* Retrieves the financial activity accounts data from `resolve`.
|
||||||
ngOnInit() {
|
* @param {ActivatedRoute} route Activated Route.
|
||||||
this.getFinancialActivityAccounts();
|
*/
|
||||||
}
|
constructor(private route: ActivatedRoute) {
|
||||||
|
this.route.data.subscribe(( data: { financialActivityAccounts: any }) => {
|
||||||
getFinancialActivityAccounts() {
|
this.financialActivityAccountData = data.financialActivityAccounts;
|
||||||
this.accountingService.getFinancialActivityAccounts().subscribe((financialActivityAccounts: any) => {
|
|
||||||
this.dataSource = new MatTableDataSource(financialActivityAccounts);
|
|
||||||
this.dataSource.paginator = this.paginator;
|
|
||||||
this.dataSource.sortingDataAccessor = (financialActivityAccount: any, property: any) => {
|
|
||||||
switch (property) {
|
|
||||||
case 'financialActivity': return financialActivityAccount.financialActivityData.name;
|
|
||||||
case 'glAccountName': return financialActivityAccount.glAccountData.name;
|
|
||||||
case 'glAccountCode': return financialActivityAccount.glAccountData.glCode;
|
|
||||||
default: return financialActivityAccount[property];
|
|
||||||
}
|
|
||||||
};
|
|
||||||
this.dataSource.sort = this.sort;
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the financial activity mappings table.
|
||||||
|
*/
|
||||||
|
ngOnInit() {
|
||||||
|
this.setFinancialActivityAccounts();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes the data source, paginator and sorter for financial activity mappings table.
|
||||||
|
*/
|
||||||
|
setFinancialActivityAccounts() {
|
||||||
|
this.dataSource = new MatTableDataSource(this.financialActivityAccountData);
|
||||||
|
this.dataSource.paginator = this.paginator;
|
||||||
|
this.dataSource.sortingDataAccessor = (financialActivityAccount: any, property: any) => {
|
||||||
|
switch (property) {
|
||||||
|
case 'financialActivity': return financialActivityAccount.financialActivityData.name;
|
||||||
|
case 'glAccountName': return financialActivityAccount.glAccountData.name;
|
||||||
|
case 'glAccountCode': return financialActivityAccount.glAccountData.glCode;
|
||||||
|
default: return financialActivityAccount[property];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
this.dataSource.sort = this.sort;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+30
@@ -0,0 +1,30 @@
|
|||||||
|
/** Angular Imports */
|
||||||
|
import { Injectable } from '@angular/core';
|
||||||
|
import { Resolve } from '@angular/router';
|
||||||
|
|
||||||
|
/** rxjs Imports */
|
||||||
|
import { Observable } from 'rxjs';
|
||||||
|
|
||||||
|
/** Custom Services */
|
||||||
|
import { AccountingService } from '../accounting.service';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Financial activity mappings data resolver.
|
||||||
|
*/
|
||||||
|
@Injectable()
|
||||||
|
export class FinancialActivityMappingsResolver implements Resolve<Object> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {AccountingService} accountingService Accounting service.
|
||||||
|
*/
|
||||||
|
constructor(private accountingService: AccountingService) {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the financial activity mappings data.
|
||||||
|
* @returns {Observable<any>}
|
||||||
|
*/
|
||||||
|
resolve(): Observable<any> {
|
||||||
|
return this.accountingService.getFinancialActivityAccounts();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+31
@@ -0,0 +1,31 @@
|
|||||||
|
/** Angular Imports */
|
||||||
|
import { Injectable } from '@angular/core';
|
||||||
|
import { Resolve, ActivatedRouteSnapshot } from '@angular/router';
|
||||||
|
|
||||||
|
/** rxjs Imports */
|
||||||
|
import { Observable } from 'rxjs';
|
||||||
|
|
||||||
|
/** Custom Services */
|
||||||
|
import { AccountingService } from '../../accounting.service';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Financial activity mapping data resolver.
|
||||||
|
*/
|
||||||
|
@Injectable()
|
||||||
|
export class FinancialActivityMappingResolver implements Resolve<Object> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {AccountingService} accountingService Accounting service.
|
||||||
|
*/
|
||||||
|
constructor(private accountingService: AccountingService) {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the financial activity mapping data.
|
||||||
|
* @returns {Observable<any>}
|
||||||
|
*/
|
||||||
|
resolve(route: ActivatedRouteSnapshot): Observable<any> {
|
||||||
|
const financialActivityAccountId = route.paramMap.get('id');
|
||||||
|
return this.accountingService.getFinancialActivityAccount(financialActivityAccountId, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+7
-5
@@ -1,9 +1,11 @@
|
|||||||
<div fxLayout="row" fxLayoutAlign="end" fxLayoutGap="2%" class="container m-b-20">
|
<div fxLayout="row" fxLayoutAlign="end" fxLayoutGap="2%" class="container m-b-20">
|
||||||
<button mat-raised-button color="primary" [routerLink]="['/accounting/financial-activity-mappings/view', financialActivityAccountId, 'edit']">
|
<button mat-raised-button color="primary" [routerLink]="['edit']">
|
||||||
<mat-icon>edit</mat-icon> Edit
|
<fa-icon icon="edit"></fa-icon>
|
||||||
|
Edit
|
||||||
</button>
|
</button>
|
||||||
<button mat-raised-button color="warn" (click)="deleteFinancialActivityAccount()">
|
<button mat-raised-button color="warn" (click)="deleteFinancialActivityAccount()">
|
||||||
<mat-icon>delete</mat-icon> Delete
|
<fa-icon icon="trash"></fa-icon>
|
||||||
|
Delete
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -20,7 +22,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div fxFlex="50%">
|
<div fxFlex="50%">
|
||||||
{{ financialActivityAccountData?.financialActivityData.name }}
|
{{ financialActivityAccount?.financialActivityData.name }}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div fxFlex="50%" class="header">
|
<div fxFlex="50%" class="header">
|
||||||
@@ -28,7 +30,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div fxFlex="50%">
|
<div fxFlex="50%">
|
||||||
{{ financialActivityAccountData?.glAccountData.name }}
|
{{ financialActivityAccount?.glAccountData.name }}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
+8
-8
@@ -1,14 +1,14 @@
|
|||||||
.container {
|
.container {
|
||||||
max-width: 37rem;
|
max-width: 37rem;
|
||||||
}
|
|
||||||
|
|
||||||
.content {
|
.content {
|
||||||
div {
|
div {
|
||||||
margin: 1rem 0;
|
margin: 1rem 0;
|
||||||
word-wrap: break-word;
|
word-wrap: break-word;
|
||||||
}
|
|
||||||
|
|
||||||
.header {
|
&.header {
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+28
-13
@@ -1,10 +1,17 @@
|
|||||||
|
/** Angular Imports */
|
||||||
import { Component, OnInit } from '@angular/core';
|
import { Component, OnInit } from '@angular/core';
|
||||||
import { ActivatedRoute, Router } from '@angular/router';
|
import { ActivatedRoute, Router } from '@angular/router';
|
||||||
import { MatDialog } from '@angular/material';
|
import { MatDialog } from '@angular/material';
|
||||||
|
|
||||||
|
/** Custom Services */
|
||||||
import { AccountingService } from '../../accounting.service';
|
import { AccountingService } from '../../accounting.service';
|
||||||
|
|
||||||
|
/** Custom Components */
|
||||||
import { DeleteDialogComponent } from '../../../shared/delete-dialog/delete-dialog.component';
|
import { DeleteDialogComponent } from '../../../shared/delete-dialog/delete-dialog.component';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* View financial activity mapping component.
|
||||||
|
*/
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'mifosx-view-financial-activity-mapping',
|
selector: 'mifosx-view-financial-activity-mapping',
|
||||||
templateUrl: './view-financial-activity-mapping.component.html',
|
templateUrl: './view-financial-activity-mapping.component.html',
|
||||||
@@ -12,26 +19,34 @@ import { DeleteDialogComponent } from '../../../shared/delete-dialog/delete-dial
|
|||||||
})
|
})
|
||||||
export class ViewFinancialActivityMappingComponent implements OnInit {
|
export class ViewFinancialActivityMappingComponent implements OnInit {
|
||||||
|
|
||||||
|
/** Financial activity account ID. */
|
||||||
financialActivityAccountId: any;
|
financialActivityAccountId: any;
|
||||||
financialActivityAccountData: any;
|
/** Financial activity account data. */
|
||||||
|
financialActivityAccount: any;
|
||||||
|
|
||||||
constructor(private route: ActivatedRoute,
|
/**
|
||||||
|
* Retrieves the financial activity account data from `resolve`.
|
||||||
|
* @param {AccountingService} accountingService Accounting Service.
|
||||||
|
* @param {ActivatedRoute} route Activated Route.
|
||||||
|
* @param {Router} router Router for navigation.
|
||||||
|
* @param {MatDialog} dialog Dialog reference.
|
||||||
|
*/
|
||||||
|
constructor(private accountingService: AccountingService,
|
||||||
|
private route: ActivatedRoute,
|
||||||
private router: Router,
|
private router: Router,
|
||||||
private accountingService: AccountingService,
|
public dialog: MatDialog) {
|
||||||
public dialog: MatDialog) { }
|
this.route.data.subscribe((data: { financialActivityAccount: any }) => {
|
||||||
|
this.financialActivityAccount = data.financialActivityAccount;
|
||||||
|
this.financialActivityAccountId = data.financialActivityAccount.id;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
this.financialActivityAccountId = this.route.snapshot.paramMap.get('id');
|
|
||||||
this.getFinancialActivityAccount();
|
|
||||||
}
|
|
||||||
|
|
||||||
getFinancialActivityAccount() {
|
|
||||||
this.accountingService.getFinancialActivityAccount(this.financialActivityAccountId, false)
|
|
||||||
.subscribe((financialActivityAccountData: any) => {
|
|
||||||
this.financialActivityAccountData = financialActivityAccountData;
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deletes the financial activity account and redirects to financial activity mappings.
|
||||||
|
*/
|
||||||
deleteFinancialActivityAccount() {
|
deleteFinancialActivityAccount() {
|
||||||
const deleteFinancialActivityAccountDialogRef = this.dialog.open(DeleteDialogComponent, {
|
const deleteFinancialActivityAccountDialogRef = this.dialog.open(DeleteDialogComponent, {
|
||||||
data: { deleteContext: `financial activity mapping ${this.financialActivityAccountId}` }
|
data: { deleteContext: `financial activity mapping ${this.financialActivityAccountId}` }
|
||||||
|
|||||||
@@ -1,140 +1,192 @@
|
|||||||
<mat-card class="container">
|
<div class="container">
|
||||||
|
|
||||||
<form [formGroup]="frequentPostingsForm" (ngSubmit)="submit()">
|
<mat-card>
|
||||||
|
|
||||||
<mat-card-content>
|
<form [formGroup]="frequentPostingsForm" (ngSubmit)="submit()">
|
||||||
|
|
||||||
<div fxLayout="row wrap" fxLayoutGap="2%" fxLayout.lt-md="column">
|
<mat-card-content>
|
||||||
|
|
||||||
<mat-form-field fxFlex="48%">
|
<div fxLayout="row wrap" fxLayoutGap="2%" fxLayout.lt-md="column">
|
||||||
<mat-select placeholder="Office" required formControlName="officeId">
|
|
||||||
<mat-option *ngFor="let office of officeData" [value]="office.id">
|
|
||||||
{{ office.name }}
|
|
||||||
</mat-option>
|
|
||||||
</mat-select>
|
|
||||||
</mat-form-field>
|
|
||||||
|
|
||||||
<mat-form-field fxFlex="48%">
|
<mat-form-field fxFlex="48%">
|
||||||
<mat-select placeholder="Accounting Rule" required formControlName="accountingRule">
|
<mat-label>Office</mat-label>
|
||||||
<mat-option *ngFor="let accountingRule of accountingRuleData" [value]="accountingRule">
|
<mat-select required formControlName="officeId">
|
||||||
{{ accountingRule.name }}
|
<mat-option *ngFor="let office of officeData" [value]="office.id">
|
||||||
</mat-option>
|
{{ office.name }}
|
||||||
</mat-select>
|
</mat-option>
|
||||||
</mat-form-field>
|
</mat-select>
|
||||||
|
<mat-error *ngIf="frequentPostingsForm.controls.officeId.hasError('required')">
|
||||||
|
Office is <strong>required</strong>
|
||||||
|
</mat-error>
|
||||||
|
</mat-form-field>
|
||||||
|
|
||||||
<mat-form-field fxFlex="48%">
|
<mat-form-field fxFlex="48%">
|
||||||
<mat-select placeholder="Currency" required formControlName="currencyCode">
|
<mat-label>Accounting Rule</mat-label>
|
||||||
<mat-option *ngFor="let currency of currencyData" [value]="currency.code">
|
<mat-select required formControlName="accountingRule">
|
||||||
{{ currency.displayLabel }}
|
<mat-option *ngFor="let accountingRule of accountingRuleData" [value]="accountingRule">
|
||||||
</mat-option>
|
{{ accountingRule.name }}
|
||||||
</mat-select>
|
</mat-option>
|
||||||
</mat-form-field>
|
</mat-select>
|
||||||
|
<mat-error *ngIf="frequentPostingsForm.controls.accountingRule.hasError('required')">
|
||||||
|
Accounting Rule is <strong>required</strong>
|
||||||
|
</mat-error>
|
||||||
|
</mat-form-field>
|
||||||
|
|
||||||
<span fxFlex="48%" fxHide.lt-md></span>
|
<mat-form-field fxFlex="48%">
|
||||||
|
<mat-label>Currency</mat-label>
|
||||||
|
<mat-select required formControlName="currencyCode">
|
||||||
|
<mat-option *ngFor="let currency of currencyData" [value]="currency.code">
|
||||||
|
{{ currency.displayLabel }}
|
||||||
|
</mat-option>
|
||||||
|
</mat-select>
|
||||||
|
<mat-error *ngIf="frequentPostingsForm.controls.currencyCode.hasError('required')">
|
||||||
|
Currency is <strong>required</strong>
|
||||||
|
</mat-error>
|
||||||
|
</mat-form-field>
|
||||||
|
|
||||||
<div fxFlexFill fxLayout="row wrap" fxLayout.lt-md="column" formArrayName="debits"
|
<span fxFlex="48%" fxHide.lt-md></span>
|
||||||
*ngFor="let debit of getFormArrayData('debits').controls; let i = index;">
|
|
||||||
|
|
||||||
<div fxFlexFill fxLayout="row wrap" fxLayoutGap="2%" fxLayout.lt-md="column" [formGroupName]="i">
|
<div fxFlexFill fxLayout="row wrap" fxLayout.lt-md="column" formArrayName="debits"
|
||||||
|
*ngFor="let debit of debits.controls; let i = index;">
|
||||||
|
|
||||||
<mat-form-field fxFlex="48%">
|
<div fxFlexFill fxLayout="row wrap" fxLayoutGap="2%" fxLayout.lt-md="column" [formGroupName]="i">
|
||||||
<mat-select placeholder="Affected GL Entry (Debit)" required formControlName="glAccountId">
|
|
||||||
<mat-option *ngFor="let affectedGLEntryDebit of debitAccountData" [value]="affectedGLEntryDebit.id">
|
|
||||||
{{ affectedGLEntryDebit.name }}
|
|
||||||
</mat-option>
|
|
||||||
</mat-select>
|
|
||||||
</mat-form-field>
|
|
||||||
|
|
||||||
<mat-form-field fxFlex="43%">
|
<mat-form-field fxFlex="48%">
|
||||||
<input type="number" matInput placeholder="Debit Amount" required formControlName="amount">
|
<mat-label>Affected GL Entry (Debit)</mat-label>
|
||||||
</mat-form-field>
|
<mat-select required formControlName="glAccountId">
|
||||||
|
<mat-option *ngFor="let affectedGLEntryDebit of debitAccountData" [value]="affectedGLEntryDebit.id">
|
||||||
|
{{ affectedGLEntryDebit.name }}
|
||||||
|
</mat-option>
|
||||||
|
</mat-select>
|
||||||
|
<mat-error *ngIf="debits.at(i).controls.glAccountId.hasError('required')">
|
||||||
|
Affected GL Entry (Debit) is <strong>required</strong>
|
||||||
|
</mat-error>
|
||||||
|
</mat-form-field>
|
||||||
|
|
||||||
<span fxFlex>
|
<mat-form-field fxFlex="43%">
|
||||||
<button *ngIf="i !== 0" type="button" mat-icon-button (click)="removeAffectedGLEntry(frequentPostingsForm.get('debits'), i)"><mat-icon>remove_circle</mat-icon></button>
|
<mat-label>Debit Amount</mat-label>
|
||||||
<button *ngIf="i === 0 && allowMultipleDebitEntries" type="button" mat-icon-button color="primary" (click)="addAffectedGLEntry(frequentPostingsForm.get('debits'))"><mat-icon>add_circle</mat-icon></button>
|
<input type="number" matInput required formControlName="amount">
|
||||||
</span>
|
<mat-error *ngIf="debits.at(i).controls.amount.hasError('required')">
|
||||||
|
Debit Amount is <strong>required</strong>
|
||||||
|
</mat-error>
|
||||||
|
</mat-form-field>
|
||||||
|
|
||||||
|
<span fxFlex>
|
||||||
|
<button *ngIf="i !== 0" type="button" mat-icon-button (click)="removeAffectedGLEntry(debits, i)">
|
||||||
|
<fa-icon icon="minus-circle" size="lg"></fa-icon>
|
||||||
|
</button>
|
||||||
|
<button *ngIf="i === 0 && allowMultipleDebitEntries" type="button" mat-icon-button color="primary" (click)="addAffectedGLEntry(debits)">
|
||||||
|
<fa-icon icon="plus-circle" size="lg"></fa-icon>
|
||||||
|
</button>
|
||||||
|
</span>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
<div fxFlexFill fxLayout="row wrap" fxLayout.lt-md="column" formArrayName="credits"
|
||||||
|
*ngFor="let credit of credits.controls; let i = index;">
|
||||||
|
|
||||||
<div fxFlexFill fxLayout="row wrap" fxLayout.lt-md="column" formArrayName="credits"
|
<div fxFlexFill fxLayout="row wrap" fxLayoutGap="2%" fxLayout.lt-md="column" [formGroupName]="i">
|
||||||
*ngFor="let credit of getFormArrayData('credits').controls; let i = index;">
|
|
||||||
|
|
||||||
<div fxFlexFill fxLayout="row wrap" fxLayoutGap="2%" fxLayout.lt-md="column" [formGroupName]="i">
|
<mat-form-field fxFlex="48%">
|
||||||
|
<mat-label>Affected GL Entry (Credit)</mat-label>
|
||||||
|
<mat-select required formControlName="glAccountId">
|
||||||
|
<mat-option *ngFor="let affectedGLEntryCredit of creditAccountData" [value]="affectedGLEntryCredit.id">
|
||||||
|
{{ affectedGLEntryCredit.name }}
|
||||||
|
</mat-option>
|
||||||
|
</mat-select>
|
||||||
|
<mat-error *ngIf="credits.at(i).controls.glAccountId.hasError('required')">
|
||||||
|
Affected GL Entry (Credit) is <strong>required</strong>
|
||||||
|
</mat-error>
|
||||||
|
</mat-form-field>
|
||||||
|
|
||||||
<mat-form-field fxFlex="48%">
|
<mat-form-field fxFlex="43%">
|
||||||
<mat-select placeholder="Affected GL Entry (Credit)" required formControlName="glAccountId">
|
<mat-label>Credit Amount</mat-label>
|
||||||
<mat-option *ngFor="let affectedGLEntryCredit of creditAccountData" [value]="affectedGLEntryCredit.id">
|
<input type="number" matInput required formControlName="amount">
|
||||||
{{ affectedGLEntryCredit.name }}
|
<mat-error *ngIf="credits.at(i).controls.amount.hasError('required')">
|
||||||
</mat-option>
|
Credit Amount is <strong>required</strong>
|
||||||
</mat-select>
|
</mat-error>
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
|
|
||||||
<mat-form-field fxFlex="43%">
|
<span fxFlex>
|
||||||
<input type="number" matInput placeholder="Credit Amount" required formControlName="amount">
|
<button *ngIf="i !== 0" type="button" mat-icon-button (click)="removeAffectedGLEntry(credits, i)">
|
||||||
</mat-form-field>
|
<fa-icon icon="minus-circle" size="lg"></fa-icon>
|
||||||
|
</button>
|
||||||
|
<button *ngIf="i === 0 && allowMultipleCreditEntries" type="button" mat-icon-button color="primary" (click)="addAffectedGLEntry(credits)">
|
||||||
|
<fa-icon icon="plus-circle" size="lg"></fa-icon>
|
||||||
|
</button>
|
||||||
|
</span>
|
||||||
|
|
||||||
<span fxFlex>
|
</div>
|
||||||
<button *ngIf="i !== 0" type="button" mat-icon-button (click)="removeAffectedGLEntry(frequentPostingsForm.get('credits'), i)"><mat-icon>remove_circle</mat-icon></button>
|
|
||||||
<button *ngIf="i === 0 && allowMultipleCreditEntries" type="button" mat-icon-button color="primary" (click)="addAffectedGLEntry(frequentPostingsForm.get('credits'))"><mat-icon>add_circle</mat-icon></button>
|
|
||||||
</span>
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<mat-form-field fxFlex="48%">
|
||||||
|
<mat-label>Reference Number</mat-label>
|
||||||
|
<input matInput formControlName="referenceNumber">
|
||||||
|
</mat-form-field>
|
||||||
|
|
||||||
|
<mat-form-field fxFlex="48%">
|
||||||
|
<mat-label>Transaction Date</mat-label>
|
||||||
|
<input matInput [min]="minDate" [max]="maxDate" [matDatepicker]="transactionDatePicker" required formControlName="transactionDate">
|
||||||
|
<mat-datepicker-toggle matSuffix [for]="transactionDatePicker"></mat-datepicker-toggle>
|
||||||
|
<mat-datepicker #transactionDatePicker></mat-datepicker>
|
||||||
|
<mat-error *ngIf="frequentPostingsForm.controls.transactionDate.hasError('required')">
|
||||||
|
Transaction Date is <strong>required</strong>
|
||||||
|
</mat-error>
|
||||||
|
</mat-form-field>
|
||||||
|
|
||||||
|
<mat-form-field fxFlex="48%">
|
||||||
|
<mat-label>Payment Type</mat-label>
|
||||||
|
<mat-select formControlName="paymentTypeId">
|
||||||
|
<mat-option *ngFor="let paymentType of paymentTypeData" [value]="paymentType.id">
|
||||||
|
{{ paymentType.name }}
|
||||||
|
</mat-option>
|
||||||
|
</mat-select>
|
||||||
|
</mat-form-field>
|
||||||
|
|
||||||
|
<mat-form-field fxFlex="48%">
|
||||||
|
<mat-label>Account Number</mat-label>
|
||||||
|
<input matInput formControlName="accountNumber">
|
||||||
|
</mat-form-field>
|
||||||
|
|
||||||
|
<mat-form-field fxFlex="48%">
|
||||||
|
<mat-label>Cheque Number</mat-label>
|
||||||
|
<input matInput formControlName="checkNumber">
|
||||||
|
</mat-form-field>
|
||||||
|
|
||||||
|
<mat-form-field fxFlex="48%">
|
||||||
|
<mat-label>Routing Code</mat-label>
|
||||||
|
<input matInput formControlName="routingCode">
|
||||||
|
</mat-form-field>
|
||||||
|
|
||||||
|
<mat-form-field fxFlex="48%">
|
||||||
|
<mat-label>Receipt Number</mat-label>
|
||||||
|
<input matInput formControlName="receiptNumber">
|
||||||
|
</mat-form-field>
|
||||||
|
|
||||||
|
<mat-form-field fxFlex="48%">
|
||||||
|
<mat-label>Bank Number</mat-label>
|
||||||
|
<input matInput formControlName="bankNumber">
|
||||||
|
</mat-form-field>
|
||||||
|
|
||||||
|
<mat-form-field fxFlex="98%">
|
||||||
|
<mat-label>Comments</mat-label>
|
||||||
|
<textarea matInput formControlName="comments"></textarea>
|
||||||
|
</mat-form-field>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<mat-form-field fxFlex="48%">
|
</mat-card-content>
|
||||||
<input matInput placeholder="Reference Number" formControlName="referenceNumber">
|
|
||||||
</mat-form-field>
|
|
||||||
|
|
||||||
<mat-form-field fxFlex="48%">
|
<mat-card-actions fxLayout="row" fxLayout.xs="column" fxLayoutAlign="center" fxLayoutGap="5px">
|
||||||
<input matInput [min]="minDate" [max]="maxDate" [matDatepicker]="transactionDatePicker" placeholder="Transaction Date" required formControlName="transactionDate">
|
<button type="button" mat-raised-button [routerLink]="['../']">Cancel</button>
|
||||||
<mat-datepicker-toggle matSuffix [for]="transactionDatePicker"></mat-datepicker-toggle>
|
<button mat-raised-button color="primary" [disabled]="!frequentPostingsForm.valid">Submit</button>
|
||||||
<mat-datepicker #transactionDatePicker></mat-datepicker>
|
</mat-card-actions>
|
||||||
</mat-form-field>
|
|
||||||
|
|
||||||
<mat-form-field fxFlex="48%">
|
</form>
|
||||||
<mat-select placeholder="Payment Type" formControlName="paymentTypeId">
|
|
||||||
<mat-option *ngFor="let paymentType of paymentTypeData" [value]="paymentType.id">
|
|
||||||
{{ paymentType.name }}
|
|
||||||
</mat-option>
|
|
||||||
</mat-select>
|
|
||||||
</mat-form-field>
|
|
||||||
|
|
||||||
<mat-form-field fxFlex="48%">
|
</mat-card>
|
||||||
<input matInput placeholder="Account Number" formControlName="accountNumber">
|
|
||||||
</mat-form-field>
|
|
||||||
|
|
||||||
<mat-form-field fxFlex="48%">
|
</div>
|
||||||
<input matInput placeholder="Cheque Number" formControlName="checkNumber">
|
|
||||||
</mat-form-field>
|
|
||||||
|
|
||||||
<mat-form-field fxFlex="48%">
|
|
||||||
<input matInput placeholder="Routing Code" formControlName="routingCode">
|
|
||||||
</mat-form-field>
|
|
||||||
|
|
||||||
<mat-form-field fxFlex="48%">
|
|
||||||
<input matInput placeholder="Receipt Number" formControlName="receiptNumber">
|
|
||||||
</mat-form-field>
|
|
||||||
|
|
||||||
<mat-form-field fxFlex="48%">
|
|
||||||
<input matInput placeholder="Bank Number" formControlName="bankNumber">
|
|
||||||
</mat-form-field>
|
|
||||||
|
|
||||||
<mat-form-field fxFlex="98%">
|
|
||||||
<textarea matInput placeholder="Comments" formControlName="comments"></textarea>
|
|
||||||
</mat-form-field>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</mat-card-content>
|
|
||||||
|
|
||||||
<mat-card-actions fxLayout="row" fxLayout.xs="column" fxLayoutAlign="center" fxLayoutGap="5px">
|
|
||||||
<button type="button" mat-raised-button [routerLink]="['/accounting']">Cancel</button>
|
|
||||||
<button mat-raised-button color="primary">Submit</button>
|
|
||||||
</mat-card-actions>
|
|
||||||
|
|
||||||
</form>
|
|
||||||
|
|
||||||
</mat-card>
|
|
||||||
|
|||||||
@@ -1,9 +1,14 @@
|
|||||||
|
/** Angular Imports */
|
||||||
import { Component, OnInit } from '@angular/core';
|
import { Component, OnInit } from '@angular/core';
|
||||||
import { FormGroup, FormBuilder, Validators, FormArray } from '@angular/forms';
|
import { FormGroup, FormBuilder, Validators, FormArray } from '@angular/forms';
|
||||||
import { Router } from '@angular/router';
|
import { Router, ActivatedRoute } from '@angular/router';
|
||||||
|
|
||||||
|
/** Custom Services */
|
||||||
import { AccountingService } from '../accounting.service';
|
import { AccountingService } from '../accounting.service';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Frequent Postings component.
|
||||||
|
*/
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'mifosx-frequent-postings',
|
selector: 'mifosx-frequent-postings',
|
||||||
templateUrl: './frequent-postings.component.html',
|
templateUrl: './frequent-postings.component.html',
|
||||||
@@ -11,35 +16,64 @@ import { AccountingService } from '../accounting.service';
|
|||||||
})
|
})
|
||||||
export class FrequentPostingsComponent implements OnInit {
|
export class FrequentPostingsComponent implements OnInit {
|
||||||
|
|
||||||
// TODO: Validations
|
/** Minimum transaction date allowed. */
|
||||||
// https://github.com/openMF/incubator-fineract/blob/master/fineract-provider/src/main/java/org/apache/fineract/accounting/journalentry/exception/JournalEntryInvalidException.java
|
|
||||||
|
|
||||||
minDate = new Date(2000, 0, 1);
|
minDate = new Date(2000, 0, 1);
|
||||||
|
/** Maximum transaction date allowed. */
|
||||||
maxDate = new Date();
|
maxDate = new Date();
|
||||||
|
/** Frequent postings form. */
|
||||||
frequentPostingsForm: FormGroup;
|
frequentPostingsForm: FormGroup;
|
||||||
|
/** Office data. */
|
||||||
officeData: any;
|
officeData: any;
|
||||||
|
/** Accounting rule data. */
|
||||||
accountingRuleData: any;
|
accountingRuleData: any;
|
||||||
|
/** Currency data. */
|
||||||
currencyData: any;
|
currencyData: any;
|
||||||
|
/** Payment type data. */
|
||||||
paymentTypeData: any;
|
paymentTypeData: any;
|
||||||
|
/** Debit account data. */
|
||||||
debitAccountData: any;
|
debitAccountData: any;
|
||||||
|
/** Credit account data. */
|
||||||
creditAccountData: any;
|
creditAccountData: any;
|
||||||
|
/** True if multiple credit entries are allowed. */
|
||||||
allowMultipleCreditEntries: boolean;
|
allowMultipleCreditEntries: boolean;
|
||||||
|
/** True if multiple debit entries are allowed. */
|
||||||
allowMultipleDebitEntries: boolean;
|
allowMultipleDebitEntries: boolean;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the offices, accounting rules, currencies and payment types data from `resolve`.
|
||||||
|
* @param {FormBuilder} formBuilder Form Builder.
|
||||||
|
* @param {AccountingService} accountingService Accounting Service.
|
||||||
|
* @param {ActivatedRoute} route Activated Route.
|
||||||
|
* @param {Router} router Router for navigation.
|
||||||
|
*/
|
||||||
constructor(private formBuilder: FormBuilder,
|
constructor(private formBuilder: FormBuilder,
|
||||||
private accountingService: AccountingService,
|
private accountingService: AccountingService,
|
||||||
private router: Router) { }
|
private route: ActivatedRoute,
|
||||||
|
private router: Router) {
|
||||||
|
this.route.data.subscribe((data: {
|
||||||
|
offices: any,
|
||||||
|
accountingRules: any,
|
||||||
|
currencies: any,
|
||||||
|
paymentTypes: any
|
||||||
|
}) => {
|
||||||
|
this.officeData = data.offices;
|
||||||
|
this.accountingRuleData = data.accountingRules;
|
||||||
|
this.currencyData = data.currencies.selectedCurrencyOptions;
|
||||||
|
this.paymentTypeData = data.paymentTypes;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates the frequent postings form and sets the affected gl entry form array.
|
||||||
|
*/
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
this.createFrequentPostingsForm();
|
this.createFrequentPostingsForm();
|
||||||
this.setAffectedGLEntryForm();
|
this.setAffectedGLEntryForm();
|
||||||
this.getOffices();
|
|
||||||
this.getAccountingRules();
|
|
||||||
this.getCurrencies();
|
|
||||||
this.getPaymentTypes();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates the frequent postings form.
|
||||||
|
*/
|
||||||
createFrequentPostingsForm() {
|
createFrequentPostingsForm() {
|
||||||
this.frequentPostingsForm = this.formBuilder.group({
|
this.frequentPostingsForm = this.formBuilder.group({
|
||||||
'officeId': ['', Validators.required],
|
'officeId': ['', Validators.required],
|
||||||
@@ -59,25 +93,30 @@ export class FrequentPostingsComponent implements OnInit {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the affected gl entry form array.
|
||||||
|
*/
|
||||||
setAffectedGLEntryForm() {
|
setAffectedGLEntryForm() {
|
||||||
this.frequentPostingsForm.get('accountingRule').valueChanges.subscribe(accountingRule => {
|
this.frequentPostingsForm.get('accountingRule').valueChanges.subscribe(accountingRule => {
|
||||||
const debits = this.frequentPostingsForm.get('debits') as FormArray;
|
while (this.debits.length) {
|
||||||
const credits = this.frequentPostingsForm.get('credits') as FormArray;
|
this.debits.removeAt(0);
|
||||||
while (debits.length) {
|
|
||||||
debits.removeAt(0);
|
|
||||||
}
|
}
|
||||||
while (credits.length) {
|
while (this.credits.length) {
|
||||||
credits.removeAt(0);
|
this.credits.removeAt(0);
|
||||||
}
|
}
|
||||||
this.allowMultipleDebitEntries = accountingRule.allowMultipleDebitEntries;
|
this.allowMultipleDebitEntries = accountingRule.allowMultipleDebitEntries;
|
||||||
this.allowMultipleCreditEntries = accountingRule.allowMultipleCreditEntries;
|
this.allowMultipleCreditEntries = accountingRule.allowMultipleCreditEntries;
|
||||||
this.debitAccountData = accountingRule.debitAccounts;
|
this.debitAccountData = accountingRule.debitAccounts;
|
||||||
this.creditAccountData = accountingRule.creditAccounts;
|
this.creditAccountData = accountingRule.creditAccounts;
|
||||||
this.addAffectedGLEntry(debits);
|
this.addAffectedGLEntry(this.debits);
|
||||||
this.addAffectedGLEntry(credits);
|
this.addAffectedGLEntry(this.credits);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates the affected gl entry form.
|
||||||
|
* @returns {FormGroup} Affected gl entry form.
|
||||||
|
*/
|
||||||
createAffectedGLEntryForm(): FormGroup {
|
createAffectedGLEntryForm(): FormGroup {
|
||||||
return this.formBuilder.group({
|
return this.formBuilder.group({
|
||||||
'glAccountId': ['', Validators.required],
|
'glAccountId': ['', Validators.required],
|
||||||
@@ -85,51 +124,63 @@ export class FrequentPostingsComponent implements OnInit {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
getFormArrayData(type: string): FormArray {
|
/**
|
||||||
return <FormArray>this.frequentPostingsForm.get(type);
|
* Gets the affected gl entry (debits) form array.
|
||||||
|
* @returns {FormArray} Debits form array.
|
||||||
|
*/
|
||||||
|
get debits(): FormArray {
|
||||||
|
return this.frequentPostingsForm.get('debits') as FormArray;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the affected gl entry (credits) form array.
|
||||||
|
* @returns {FormArray} Credits form array.
|
||||||
|
*/
|
||||||
|
get credits(): FormArray {
|
||||||
|
return this.frequentPostingsForm.get('credits') as FormArray;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds the affected gl entry form to given affected gl entry form array.
|
||||||
|
* @param {FormArray} affectedGLEntryFormArray Given affected gl entry form array (debit/credit).
|
||||||
|
*/
|
||||||
addAffectedGLEntry(affectedGLEntryFormArray: FormArray) {
|
addAffectedGLEntry(affectedGLEntryFormArray: FormArray) {
|
||||||
affectedGLEntryFormArray.push(this.createAffectedGLEntryForm());
|
affectedGLEntryFormArray.push(this.createAffectedGLEntryForm());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes the affected gl entry form from given affected gl entry form array at given index.
|
||||||
|
* @param {FormArray} affectedGLEntryFormArray Given affected gl entry form array (debit/credit).
|
||||||
|
* @param {number} index Array index from where affected gl entry form needs to be removed.
|
||||||
|
*/
|
||||||
removeAffectedGLEntry(affectedGLEntryFormArray: FormArray, index: number) {
|
removeAffectedGLEntry(affectedGLEntryFormArray: FormArray, index: number) {
|
||||||
affectedGLEntryFormArray.removeAt(index);
|
affectedGLEntryFormArray.removeAt(index);
|
||||||
}
|
}
|
||||||
|
|
||||||
getOffices() {
|
/**
|
||||||
this.accountingService.getOffices().subscribe(officeData => {
|
* Submits the frequent postings form and creates journal entry,
|
||||||
this.officeData = officeData;
|
* if successful redirects to view created transaction.
|
||||||
});
|
*/
|
||||||
}
|
|
||||||
|
|
||||||
getAccountingRules() {
|
|
||||||
this.accountingService.getAccountingRules(true).subscribe(accountingRuleData => {
|
|
||||||
this.accountingRuleData = accountingRuleData;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
getCurrencies() {
|
|
||||||
this.accountingService.getCurrencies().subscribe(currencyData => {
|
|
||||||
this.currencyData = currencyData.selectedCurrencyOptions;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
getPaymentTypes() {
|
|
||||||
this.accountingService.getPaymentTypes().subscribe(paymentTypeData => {
|
|
||||||
this.paymentTypeData = paymentTypeData;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
submit() {
|
submit() {
|
||||||
const journalEntry = this.frequentPostingsForm.value;
|
const journalEntry = this.frequentPostingsForm.value;
|
||||||
journalEntry.accountingRule = journalEntry.accountingRule.id;
|
journalEntry.accountingRule = journalEntry.accountingRule.id;
|
||||||
// TODO: Update once language and date settings are setup
|
// TODO: Update once language and date settings are setup
|
||||||
journalEntry.locale = 'en';
|
journalEntry.locale = 'en';
|
||||||
journalEntry.dateFormat = 'dd MMMM yyyy';
|
journalEntry.dateFormat = 'yyyy-MM-dd';
|
||||||
journalEntry.transactionDate = '20 July 2018';
|
if (journalEntry.transactionDate instanceof Date) {
|
||||||
|
let day = journalEntry.transactionDate.getDate();
|
||||||
|
let month = journalEntry.transactionDate.getMonth() + 1;
|
||||||
|
const year = journalEntry.transactionDate.getFullYear();
|
||||||
|
if (day < 10) {
|
||||||
|
day = `0${day}`;
|
||||||
|
}
|
||||||
|
if (month < 10) {
|
||||||
|
month = `0${month}`;
|
||||||
|
}
|
||||||
|
journalEntry.transactionDate = `${year}-${month}-${day}`;
|
||||||
|
}
|
||||||
this.accountingService.createJournalEntry(journalEntry).subscribe(response => {
|
this.accountingService.createJournalEntry(journalEntry).subscribe(response => {
|
||||||
this.router.navigate(['/accounting/transactions/view', response.transactionId]);
|
this.router.navigate(['../transactions/view', response.transactionId], { relativeTo: this.route });
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+23
-8
@@ -1,3 +1,4 @@
|
|||||||
|
<!-- TODO: Responsiveness/design enhancement and reduction in form loading time -->
|
||||||
<div class="container">
|
<div class="container">
|
||||||
|
|
||||||
<mat-card>
|
<mat-card>
|
||||||
@@ -9,11 +10,15 @@
|
|||||||
<div fxLayout="row wrap" fxLayoutGap="2%" fxLayout.lt-md="column">
|
<div fxLayout="row wrap" fxLayoutGap="2%" fxLayout.lt-md="column">
|
||||||
|
|
||||||
<mat-form-field fxFlex="88%">
|
<mat-form-field fxFlex="88%">
|
||||||
<mat-select placeholder="Office" required formControlName="officeId">
|
<mat-label>Office</mat-label>
|
||||||
|
<mat-select required formControlName="officeId">
|
||||||
<mat-option *ngFor="let office of officeData" [value]="office.id">
|
<mat-option *ngFor="let office of officeData" [value]="office.id">
|
||||||
{{ office.name }}
|
{{ office.name }}
|
||||||
</mat-option>
|
</mat-option>
|
||||||
</mat-select>
|
</mat-select>
|
||||||
|
<mat-error *ngIf="openingBalancesForm.controls.officeId.hasError('required')">
|
||||||
|
Office is <strong>required</strong>
|
||||||
|
</mat-error>
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
|
|
||||||
<button mat-button type="button" color="primary" fxFlex="4%" (click)="retrieveOpeningBalances()">Retrieve</button>
|
<button mat-button type="button" color="primary" fxFlex="4%" (click)="retrieveOpeningBalances()">Retrieve</button>
|
||||||
@@ -25,17 +30,25 @@
|
|||||||
<label fxFlex="98%" class="content"><span class="header">Opening Balances Contra Account:</span> {{ openingBalancesData.contraAccount.name + ' (' + openingBalancesData.contraAccount.glCode + ')' }}</label>
|
<label fxFlex="98%" class="content"><span class="header">Opening Balances Contra Account:</span> {{ openingBalancesData.contraAccount.name + ' (' + openingBalancesData.contraAccount.glCode + ')' }}</label>
|
||||||
|
|
||||||
<mat-form-field fxFlex="48%">
|
<mat-form-field fxFlex="48%">
|
||||||
<mat-select placeholder="Currency" required formControlName="currencyCode">
|
<mat-label>Currency</mat-label>
|
||||||
|
<mat-select required formControlName="currencyCode">
|
||||||
<mat-option *ngFor="let currency of currencyData" [value]="currency.code">
|
<mat-option *ngFor="let currency of currencyData" [value]="currency.code">
|
||||||
{{ currency.displayLabel }}
|
{{ currency.displayLabel }}
|
||||||
</mat-option>
|
</mat-option>
|
||||||
</mat-select>
|
</mat-select>
|
||||||
|
<mat-error *ngIf="openingBalancesForm.controls.currencyCode.hasError('required')">
|
||||||
|
Currency is <strong>required</strong>
|
||||||
|
</mat-error>
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
|
|
||||||
<mat-form-field fxFlex="48%">
|
<mat-form-field fxFlex="48%">
|
||||||
<input matInput [min]="minDate" [max]="maxDate" [matDatepicker]="openingBalancesDatePicker" placeholder="Opening Balances Date" required formControlName="transactionDate">
|
<mat-label>Opening Balances Date</mat-label>
|
||||||
|
<input matInput [min]="minDate" [max]="maxDate" [matDatepicker]="openingBalancesDatePicker" required formControlName="transactionDate">
|
||||||
<mat-datepicker-toggle matSuffix [for]="openingBalancesDatePicker"></mat-datepicker-toggle>
|
<mat-datepicker-toggle matSuffix [for]="openingBalancesDatePicker"></mat-datepicker-toggle>
|
||||||
<mat-datepicker #openingBalancesDatePicker></mat-datepicker>
|
<mat-datepicker #openingBalancesDatePicker></mat-datepicker>
|
||||||
|
<mat-error *ngIf="openingBalancesForm.controls.transactionDate.hasError('required')">
|
||||||
|
Opening Balances Date is <strong>required</strong>
|
||||||
|
</mat-error>
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
|
|
||||||
<div fxLayout="row wrap" fxLayoutGap="2%" fxLayout.lt-md="column" class="content" fxFlex="100%">
|
<div fxLayout="row wrap" fxLayoutGap="2%" fxLayout.lt-md="column" class="content" fxFlex="100%">
|
||||||
@@ -63,7 +76,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div fxFlexFill fxLayout="row wrap" fxLayout.lt-md="column" class="content" formArrayName="glAccountEntries"
|
<div fxFlexFill fxLayout="row wrap" fxLayout.lt-md="column" class="content" formArrayName="glAccountEntries"
|
||||||
*ngFor="let credit of getFormArrayData('glAccountEntries').controls; let i = index;">
|
*ngFor="let credit of glAccountEntries.controls; let i = index;">
|
||||||
|
|
||||||
<div fxFlexFill fxLayout="row wrap" fxLayoutGap="2%" fxLayout.lt-md="column" [formGroupName]="i">
|
<div fxFlexFill fxLayout="row wrap" fxLayoutGap="2%" fxLayout.lt-md="column" [formGroupName]="i">
|
||||||
|
|
||||||
@@ -81,13 +94,15 @@
|
|||||||
|
|
||||||
<div fxFlex="23%">
|
<div fxFlex="23%">
|
||||||
<mat-form-field>
|
<mat-form-field>
|
||||||
<input matInput type="number" placeholder="Debit" formControlName="debit">
|
<mat-label>Debit</mat-label>
|
||||||
|
<input matInput type="number" formControlName="debit">
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div fxFlex="23%">
|
<div fxFlex="23%">
|
||||||
<mat-form-field>
|
<mat-form-field>
|
||||||
<input matInput type="number" placeholder="Credit" formControlName="credit">
|
<mat-label>Credit</mat-label>
|
||||||
|
<input matInput type="number" formControlName="credit">
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -100,8 +115,8 @@
|
|||||||
</mat-card-content>
|
</mat-card-content>
|
||||||
|
|
||||||
<mat-card-actions fxLayout="row" fxLayout.xs="column" fxLayoutAlign="center" fxLayoutGap="5px" *ngIf="openingBalancesData">
|
<mat-card-actions fxLayout="row" fxLayout.xs="column" fxLayoutAlign="center" fxLayoutGap="5px" *ngIf="openingBalancesData">
|
||||||
<button type="button" mat-raised-button [routerLink]="['/accounting']">Cancel</button>
|
<button type="button" mat-raised-button [routerLink]="['../']">Cancel</button>
|
||||||
<button mat-raised-button color="primary">Submit</button>
|
<button mat-raised-button color="primary" [disabled]="!openingBalancesForm.valid">Submit</button>
|
||||||
</mat-card-actions>
|
</mat-card-actions>
|
||||||
|
|
||||||
</form>
|
</form>
|
||||||
|
|||||||
@@ -2,9 +2,9 @@
|
|||||||
div {
|
div {
|
||||||
margin: 1rem 0;
|
margin: 1rem 0;
|
||||||
word-wrap: break-word;
|
word-wrap: break-word;
|
||||||
}
|
|
||||||
|
|
||||||
.header {
|
&.header {
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,14 +1,17 @@
|
|||||||
|
/** Angular Imports */
|
||||||
import { Component, OnInit } from '@angular/core';
|
import { Component, OnInit } from '@angular/core';
|
||||||
import { FormGroup, FormBuilder, Validators, FormArray, ValidatorFn, ValidationErrors } from '@angular/forms';
|
import { FormGroup, FormBuilder, Validators, FormArray } from '@angular/forms';
|
||||||
|
import { ActivatedRoute, Router } from '@angular/router';
|
||||||
|
|
||||||
|
/** Custom Services */
|
||||||
import { AccountingService } from '../accounting.service';
|
import { AccountingService } from '../accounting.service';
|
||||||
|
|
||||||
const onlyOneOfTheFieldsIsRequiredValidator: ValidatorFn = (glAccountEntriesForm: FormGroup): ValidationErrors | null => {
|
/** Custom Validators */
|
||||||
const debit = glAccountEntriesForm.controls.debit.value;
|
import { onlyOneOfTheFieldsIsRequiredValidator } from './only-one-of-the-fields-is-required.validator';
|
||||||
const credit = glAccountEntriesForm.controls.credit.value;
|
|
||||||
return ((debit || credit) && !(debit && credit)) ? null : { 'error': true };
|
|
||||||
};
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Migrate opening balances component.
|
||||||
|
*/
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'mifosx-migrate-opening-balances',
|
selector: 'mifosx-migrate-opening-balances',
|
||||||
templateUrl: './migrate-opening-balances.component.html',
|
templateUrl: './migrate-opening-balances.component.html',
|
||||||
@@ -16,37 +19,53 @@ const onlyOneOfTheFieldsIsRequiredValidator: ValidatorFn = (glAccountEntriesForm
|
|||||||
})
|
})
|
||||||
export class MigrateOpeningBalancesComponent implements OnInit {
|
export class MigrateOpeningBalancesComponent implements OnInit {
|
||||||
|
|
||||||
|
/** Minimum opening balances date allowed. */
|
||||||
minDate = new Date(2000, 0, 1);
|
minDate = new Date(2000, 0, 1);
|
||||||
|
/** Maximum opening balances date allowed. */
|
||||||
maxDate = new Date();
|
maxDate = new Date();
|
||||||
|
/** Opening balances form. */
|
||||||
openingBalancesForm: FormGroup;
|
openingBalancesForm: FormGroup;
|
||||||
|
/** Opening balances data. */
|
||||||
openingBalancesData: any;
|
openingBalancesData: any;
|
||||||
|
/** Office data. */
|
||||||
officeData: any;
|
officeData: any;
|
||||||
|
/** Currency data. */
|
||||||
currencyData: any;
|
currencyData: any;
|
||||||
|
/** Sum total of debits. */
|
||||||
debitsSum = 0;
|
debitsSum = 0;
|
||||||
|
/** Sum total of credits. */
|
||||||
creditsSum = 0;
|
creditsSum = 0;
|
||||||
|
|
||||||
constructor(private accountingService: AccountingService,
|
/**
|
||||||
private formBuilder: FormBuilder) { }
|
* Retrieves the offices and currencies from `resolve`.
|
||||||
|
* @param {FormBuilder} formBuilder Form Builder.
|
||||||
|
* @param {AccountingService} accountingService Accounting Service.
|
||||||
|
* @param {ActivatedRoute} route Activated Route.
|
||||||
|
* @param {Router} router Router for navigation.
|
||||||
|
*/
|
||||||
|
constructor(private formBuilder: FormBuilder,
|
||||||
|
private accountingService: AccountingService,
|
||||||
|
private route: ActivatedRoute,
|
||||||
|
private router: Router) {
|
||||||
|
this.route.data.subscribe((data: {
|
||||||
|
offices: any,
|
||||||
|
currencies: any
|
||||||
|
}) => {
|
||||||
|
this.officeData = data.offices;
|
||||||
|
this.currencyData = data.currencies.selectedCurrencyOptions;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates the opening balances form. (initially retrieves gl accounts on the basis of specified office)
|
||||||
|
*/
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
this.createOpeningBalancesForm();
|
this.createOpeningBalancesForm();
|
||||||
this.getOffices();
|
|
||||||
this.getCurrencies();
|
|
||||||
}
|
|
||||||
|
|
||||||
getOffices() {
|
|
||||||
this.accountingService.getOffices().subscribe(officeData => {
|
|
||||||
this.officeData = officeData;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
getCurrencies() {
|
|
||||||
this.accountingService.getCurrencies().subscribe(currencyData => {
|
|
||||||
this.currencyData = currencyData.selectedCurrencyOptions;
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates the opening balances form.
|
||||||
|
*/
|
||||||
createOpeningBalancesForm() {
|
createOpeningBalancesForm() {
|
||||||
this.openingBalancesForm = this.formBuilder.group({
|
this.openingBalancesForm = this.formBuilder.group({
|
||||||
'officeId': ['', Validators.required],
|
'officeId': ['', Validators.required],
|
||||||
@@ -56,6 +75,11 @@ export class MigrateOpeningBalancesComponent implements OnInit {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates the gl account entry form.
|
||||||
|
* @param glAccount GL Account for which form is returned.
|
||||||
|
* @returns {FormGroup} GL Account entry form.
|
||||||
|
*/
|
||||||
createGLAccountEntryForm(glAccount: any): FormGroup {
|
createGLAccountEntryForm(glAccount: any): FormGroup {
|
||||||
return this.formBuilder.group({
|
return this.formBuilder.group({
|
||||||
'glAccountId': [glAccount.glAccountId],
|
'glAccountId': [glAccount.glAccountId],
|
||||||
@@ -64,19 +88,32 @@ export class MigrateOpeningBalancesComponent implements OnInit {
|
|||||||
}, { validator: onlyOneOfTheFieldsIsRequiredValidator });
|
}, { validator: onlyOneOfTheFieldsIsRequiredValidator });
|
||||||
}
|
}
|
||||||
|
|
||||||
getFormArrayData(type: string): FormArray {
|
/**
|
||||||
return <FormArray>this.openingBalancesForm.get(type);
|
* Gets the gl account entries form array.
|
||||||
|
* @returns {FormArray} GL Account entries form array.
|
||||||
|
*/
|
||||||
|
get glAccountEntries(): FormArray {
|
||||||
|
return this.openingBalancesForm.get('glAccountEntries') as FormArray;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves gl accounts on the basis of specified office.
|
||||||
|
*/
|
||||||
retrieveOpeningBalances() {
|
retrieveOpeningBalances() {
|
||||||
this.accountingService.retrieveOpeningBalances(this.openingBalancesForm.value.officeId)
|
this.accountingService.retrieveOpeningBalances(this.openingBalancesForm.value.officeId)
|
||||||
.subscribe((openingBalancesData: any) => {
|
.subscribe((openingBalancesData: any) => {
|
||||||
const entry = this.openingBalancesForm.get('glAccountEntries') as FormArray;
|
const entry = this.openingBalancesForm.get('glAccountEntries') as FormArray;
|
||||||
|
|
||||||
openingBalancesData.glAccounts = openingBalancesData.assetAccountOpeningBalances
|
openingBalancesData.glAccounts = openingBalancesData.assetAccountOpeningBalances
|
||||||
.concat(openingBalancesData.liabityAccountOpeningBalances, openingBalancesData.equityAccountOpeningBalances, openingBalancesData.incomeAccountOpeningBalances, openingBalancesData.expenseAccountOpeningBalances);
|
.concat(openingBalancesData.liabityAccountOpeningBalances,
|
||||||
|
openingBalancesData.equityAccountOpeningBalances,
|
||||||
|
openingBalancesData.incomeAccountOpeningBalances,
|
||||||
|
openingBalancesData.expenseAccountOpeningBalances);
|
||||||
|
|
||||||
openingBalancesData.glAccounts.forEach((glAccount: any) => {
|
openingBalancesData.glAccounts.forEach((glAccount: any) => {
|
||||||
entry.push(this.createGLAccountEntryForm(glAccount));
|
entry.push(this.createGLAccountEntryForm(glAccount));
|
||||||
});
|
});
|
||||||
|
|
||||||
this.openingBalancesData = openingBalancesData;
|
this.openingBalancesData = openingBalancesData;
|
||||||
|
|
||||||
entry.valueChanges.subscribe(() => {
|
entry.valueChanges.subscribe(() => {
|
||||||
@@ -90,32 +127,41 @@ export class MigrateOpeningBalancesComponent implements OnInit {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Submits the opening balances form and defines opening balances,
|
||||||
|
* if successful redirects to view created transaction.
|
||||||
|
*/
|
||||||
submit() {
|
submit() {
|
||||||
// TODO: Validate
|
const openingBalances = this.openingBalancesForm.value;
|
||||||
if (this.openingBalancesForm.status !== 'INVALID') {
|
// TODO: Update once language and date settings are setup
|
||||||
const openingBalances = this.openingBalancesForm.value;
|
openingBalances.locale = 'en';
|
||||||
// TODO: Update once language and date settings are setup
|
openingBalances.dateFormat = 'yyyy-MM-dd';
|
||||||
openingBalances.locale = 'en';
|
if (openingBalances.transactionDate instanceof Date) {
|
||||||
openingBalances.dateFormat = 'dd MMMM yyyy';
|
let day = openingBalances.transactionDate.getDate();
|
||||||
openingBalances.transactionDate = '07 August 2018';
|
let month = openingBalances.transactionDate.getMonth() + 1;
|
||||||
openingBalances.debits = [];
|
const year = openingBalances.transactionDate.getFullYear();
|
||||||
openingBalances.credits = [];
|
if (day < 10) {
|
||||||
this.openingBalancesForm.value.glAccountEntries.forEach((entry: any) => {
|
day = `0${day}`;
|
||||||
if (entry.debit) {
|
}
|
||||||
openingBalances.debits.push({ glAccountId: entry.glAccountId, amount: entry.debit });
|
if (month < 10) {
|
||||||
}
|
month = `0${month}`;
|
||||||
if (entry.credit) {
|
}
|
||||||
openingBalances.credits.push({ glAccountId: entry.glAccountId, amount: entry.credit });
|
openingBalances.transactionDate = `${year}-${month}-${day}`;
|
||||||
}
|
|
||||||
});
|
|
||||||
delete openingBalances.glAccountEntries;
|
|
||||||
this.accountingService.defineOpeningBalances(openingBalances)
|
|
||||||
.subscribe((response: any) => {
|
|
||||||
console.log(response);
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
console.log('Errors exist in form!');
|
|
||||||
}
|
}
|
||||||
|
openingBalances.debits = [];
|
||||||
|
openingBalances.credits = [];
|
||||||
|
this.openingBalancesForm.value.glAccountEntries.forEach((entry: any) => {
|
||||||
|
if (entry.debit) {
|
||||||
|
openingBalances.debits.push({ glAccountId: entry.glAccountId, amount: entry.debit });
|
||||||
|
}
|
||||||
|
if (entry.credit) {
|
||||||
|
openingBalances.credits.push({ glAccountId: entry.glAccountId, amount: entry.credit });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
delete openingBalances.glAccountEntries;
|
||||||
|
this.accountingService.defineOpeningBalances(openingBalances).subscribe((response: any) => {
|
||||||
|
this.router.navigate(['/accounting/journal-entries/transactions/view', response.transactionId]);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+9
@@ -0,0 +1,9 @@
|
|||||||
|
/** Angular Imports */
|
||||||
|
import { FormGroup, ValidatorFn, ValidationErrors } from '@angular/forms';
|
||||||
|
|
||||||
|
/** Validates that atleast one of the fields debit or credit is filled (but not both) for a given gl account. */
|
||||||
|
export const onlyOneOfTheFieldsIsRequiredValidator: ValidatorFn = (glAccountEntriesForm: FormGroup): ValidationErrors | null => {
|
||||||
|
const debit = glAccountEntriesForm.controls.debit.value;
|
||||||
|
const credit = glAccountEntriesForm.controls.credit.value;
|
||||||
|
return ((debit || credit) && !(debit && credit)) ? null : { 'error': true };
|
||||||
|
};
|
||||||
@@ -9,9 +9,13 @@
|
|||||||
<div fxLayout="row">
|
<div fxLayout="row">
|
||||||
|
|
||||||
<mat-form-field fxFlex>
|
<mat-form-field fxFlex>
|
||||||
<input matInput [min]="minDate" [max]="maxDate" [matDatepicker]="tillDatePicker" placeholder="Accrue Till Date" required formControlName="tillDate">
|
<mat-label>Accrue Till Date</mat-label>
|
||||||
|
<input matInput [min]="minDate" [max]="maxDate" [matDatepicker]="tillDatePicker" required formControlName="tillDate">
|
||||||
<mat-datepicker-toggle matSuffix [for]="tillDatePicker"></mat-datepicker-toggle>
|
<mat-datepicker-toggle matSuffix [for]="tillDatePicker"></mat-datepicker-toggle>
|
||||||
<mat-datepicker #tillDatePicker></mat-datepicker>
|
<mat-datepicker #tillDatePicker></mat-datepicker>
|
||||||
|
<mat-error *ngIf="periodicAccrualsForm.controls.tillDate.hasError('required')">
|
||||||
|
Accrue Date is <strong>required</strong>
|
||||||
|
</mat-error>
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
@@ -19,8 +23,11 @@
|
|||||||
</mat-card-content>
|
</mat-card-content>
|
||||||
|
|
||||||
<mat-card-actions fxLayout="row" fxLayout.xs="column" fxLayoutAlign="center" fxLayoutGap="5px">
|
<mat-card-actions fxLayout="row" fxLayout.xs="column" fxLayoutAlign="center" fxLayoutGap="5px">
|
||||||
<button type="button" mat-raised-button [routerLink]="['/accounting']">Cancel</button>
|
<button type="button" mat-raised-button [routerLink]="['../']">Cancel</button>
|
||||||
<button mat-raised-button color="primary"><mat-icon>play_arrow</mat-icon> Run Periodic Accruals</button>
|
<button mat-raised-button color="primary" [disabled]="!periodicAccrualsForm.valid">
|
||||||
|
<fa-icon icon="play"></fa-icon>
|
||||||
|
Run Periodic Accruals
|
||||||
|
</button>
|
||||||
</mat-card-actions>
|
</mat-card-actions>
|
||||||
|
|
||||||
</form>
|
</form>
|
||||||
|
|||||||
@@ -1,9 +1,14 @@
|
|||||||
|
/** Angular Imports */
|
||||||
import { Component, OnInit } from '@angular/core';
|
import { Component, OnInit } from '@angular/core';
|
||||||
import { FormGroup, FormBuilder, Validators } from '@angular/forms';
|
import { FormGroup, FormBuilder, Validators } from '@angular/forms';
|
||||||
import { Router } from '@angular/router';
|
import { Router, ActivatedRoute } from '@angular/router';
|
||||||
|
|
||||||
|
/** Custom Services */
|
||||||
import { AccountingService } from '../accounting.service';
|
import { AccountingService } from '../accounting.service';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Periodic accruals component.
|
||||||
|
*/
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'mifosx-periodic-accruals',
|
selector: 'mifosx-periodic-accruals',
|
||||||
templateUrl: './periodic-accruals.component.html',
|
templateUrl: './periodic-accruals.component.html',
|
||||||
@@ -11,32 +16,63 @@ import { AccountingService } from '../accounting.service';
|
|||||||
})
|
})
|
||||||
export class PeriodicAccrualsComponent implements OnInit {
|
export class PeriodicAccrualsComponent implements OnInit {
|
||||||
|
|
||||||
|
/** Minimum accrue date allowed. */
|
||||||
minDate = new Date(2000, 0, 1);
|
minDate = new Date(2000, 0, 1);
|
||||||
|
/** Maximum accrue date allowed. */
|
||||||
maxDate = new Date();
|
maxDate = new Date();
|
||||||
|
/** Periodic accruals form. */
|
||||||
periodicAccrualsForm: FormGroup;
|
periodicAccrualsForm: FormGroup;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {FormBuilder} formBuilder Form Builder.
|
||||||
|
* @param {AccountingService} accountingService Accounting Service.
|
||||||
|
* @param {ActivatedRoute} route Activated Route.
|
||||||
|
* @param {Router} router Router for navigation.
|
||||||
|
*/
|
||||||
constructor(private formBuilder: FormBuilder,
|
constructor(private formBuilder: FormBuilder,
|
||||||
private accountingService: AccountingService,
|
private accountingService: AccountingService,
|
||||||
|
private route: ActivatedRoute,
|
||||||
private router: Router) { }
|
private router: Router) { }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates periodic accruals form.
|
||||||
|
*/
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
this.createPeriodicAccrualsForm();
|
this.createPeriodicAccrualsForm();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates periodic accruals form.
|
||||||
|
*/
|
||||||
createPeriodicAccrualsForm() {
|
createPeriodicAccrualsForm() {
|
||||||
this.periodicAccrualsForm = this.formBuilder.group({
|
this.periodicAccrualsForm = this.formBuilder.group({
|
||||||
'tillDate': ['', Validators.required]
|
'tillDate': ['', Validators.required]
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Submits the periodic accruals form and executes periodic accruals,
|
||||||
|
* if successful redirects to accounting.
|
||||||
|
*/
|
||||||
submit() {
|
submit() {
|
||||||
const periodicAccruals = this.periodicAccrualsForm.value;
|
const periodicAccruals = this.periodicAccrualsForm.value;
|
||||||
// TODO: Update once language and date settings are setup
|
// TODO: Update once language and date settings are setup
|
||||||
periodicAccruals.locale = 'en';
|
periodicAccruals.locale = 'en';
|
||||||
periodicAccruals.dateFormat = 'dd MMMM yyyy';
|
periodicAccruals.dateFormat = 'yyyy-MM-dd';
|
||||||
periodicAccruals.tillDate = '06 August 2018';
|
if (periodicAccruals.tillDate instanceof Date) {
|
||||||
this.accountingService.executePeriodicAccruals(periodicAccruals).subscribe(response => {
|
let day = periodicAccruals.tillDate.getDate();
|
||||||
this.router.navigate(['/accounting']);
|
let month = periodicAccruals.tillDate.getMonth() + 1;
|
||||||
|
const year = periodicAccruals.tillDate.getFullYear();
|
||||||
|
if (day < 10) {
|
||||||
|
day = `0${day}`;
|
||||||
|
}
|
||||||
|
if (month < 10) {
|
||||||
|
month = `0${month}`;
|
||||||
|
}
|
||||||
|
periodicAccruals.tillDate = `${year}-${month}-${day}`;
|
||||||
|
}
|
||||||
|
this.accountingService.executePeriodicAccruals(periodicAccruals).subscribe(() => {
|
||||||
|
this.router.navigate(['../'], { relativeTo: this.route });
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+8
-4
@@ -2,16 +2,20 @@
|
|||||||
|
|
||||||
<mat-card>
|
<mat-card>
|
||||||
|
|
||||||
<form [formGroup]="provisioningEntriesForm" (ngSubmit)="submit()">
|
<form [formGroup]="provisioningEntryForm" (ngSubmit)="submit()">
|
||||||
|
|
||||||
<mat-card-content>
|
<mat-card-content>
|
||||||
|
|
||||||
<div fxLayout="column">
|
<div fxLayout="column">
|
||||||
|
|
||||||
<mat-form-field fxFlex>
|
<mat-form-field fxFlex>
|
||||||
<input matInput [min]="minDate" [max]="maxDate" [matDatepicker]="datePicker" placeholder="Date" required formControlName="date">
|
<mat-label>Date</mat-label>
|
||||||
|
<input matInput [min]="minDate" [max]="maxDate" [matDatepicker]="datePicker" required formControlName="date">
|
||||||
<mat-datepicker-toggle matSuffix [for]="datePicker"></mat-datepicker-toggle>
|
<mat-datepicker-toggle matSuffix [for]="datePicker"></mat-datepicker-toggle>
|
||||||
<mat-datepicker #datePicker></mat-datepicker>
|
<mat-datepicker #datePicker></mat-datepicker>
|
||||||
|
<mat-error *ngIf="provisioningEntryForm.controls.date.hasError('required')">
|
||||||
|
Date is <strong>required</strong>
|
||||||
|
</mat-error>
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
|
|
||||||
<div fxFlex>
|
<div fxFlex>
|
||||||
@@ -25,8 +29,8 @@
|
|||||||
</mat-card-content>
|
</mat-card-content>
|
||||||
|
|
||||||
<mat-card-actions fxLayout="row" fxLayout.xs="column" fxLayoutAlign="center" fxLayoutGap="5px">
|
<mat-card-actions fxLayout="row" fxLayout.xs="column" fxLayoutAlign="center" fxLayoutGap="5px">
|
||||||
<button type="button" mat-raised-button [routerLink]="['/accounting/provisioning-entries']">Cancel</button>
|
<button type="button" mat-raised-button [routerLink]="['../']">Cancel</button>
|
||||||
<button mat-raised-button color="primary">Submit</button>
|
<button mat-raised-button color="primary" [disabled]="!provisioningEntryForm.valid">Submit</button>
|
||||||
</mat-card-actions>
|
</mat-card-actions>
|
||||||
|
|
||||||
</form>
|
</form>
|
||||||
|
|||||||
+47
-9
@@ -1,8 +1,14 @@
|
|||||||
|
/** Angular Imports */
|
||||||
import { Component, OnInit } from '@angular/core';
|
import { Component, OnInit } from '@angular/core';
|
||||||
import { FormGroup, FormBuilder, Validators } from '@angular/forms';
|
import { FormGroup, FormBuilder, Validators } from '@angular/forms';
|
||||||
|
import { ActivatedRoute, Router } from '@angular/router';
|
||||||
|
|
||||||
|
/** Custom Services */
|
||||||
import { AccountingService } from '../../accounting.service';
|
import { AccountingService } from '../../accounting.service';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create provisioning entry component.
|
||||||
|
*/
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'mifosx-create-provisioning-entry',
|
selector: 'mifosx-create-provisioning-entry',
|
||||||
templateUrl: './create-provisioning-entry.component.html',
|
templateUrl: './create-provisioning-entry.component.html',
|
||||||
@@ -10,33 +16,65 @@ import { AccountingService } from '../../accounting.service';
|
|||||||
})
|
})
|
||||||
export class CreateProvisioningEntryComponent implements OnInit {
|
export class CreateProvisioningEntryComponent implements OnInit {
|
||||||
|
|
||||||
|
/** Minimum provisioning date allowed. */
|
||||||
minDate = new Date(2000, 0, 1);
|
minDate = new Date(2000, 0, 1);
|
||||||
|
/** Maximum provisioning date allowed. */
|
||||||
maxDate = new Date();
|
maxDate = new Date();
|
||||||
provisioningEntriesForm: FormGroup;
|
/** Provisioning entry form. */
|
||||||
|
provisioningEntryForm: FormGroup;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {FormBuilder} formBuilder Form Builder.
|
||||||
|
* @param {AccountingService} accountingService Accounting Service.
|
||||||
|
* @param {ActivatedRoute} route Activated Route.
|
||||||
|
* @param {Router} router Router for navigation.
|
||||||
|
*/
|
||||||
constructor(private formBuilder: FormBuilder,
|
constructor(private formBuilder: FormBuilder,
|
||||||
private accountingService: AccountingService) { }
|
private accountingService: AccountingService,
|
||||||
|
private route: ActivatedRoute,
|
||||||
|
private router: Router) { }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates the provisioning entry form.
|
||||||
|
*/
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
this.createProvisioningEntriesForm();
|
this.createProvisioningEntryForm();
|
||||||
}
|
}
|
||||||
|
|
||||||
createProvisioningEntriesForm() {
|
/**
|
||||||
this.provisioningEntriesForm = this.formBuilder.group({
|
* Creates the provisioning entry form.
|
||||||
|
*/
|
||||||
|
createProvisioningEntryForm() {
|
||||||
|
this.provisioningEntryForm = this.formBuilder.group({
|
||||||
'date': ['', Validators.required],
|
'date': ['', Validators.required],
|
||||||
'createjournalentries': [false]
|
'createjournalentries': [false]
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Submits the provisioning entry form and creates provisioning entry,
|
||||||
|
* if successful redirects to view created entry.
|
||||||
|
*/
|
||||||
submit() {
|
submit() {
|
||||||
const provisioningEntry = this.provisioningEntriesForm.value;
|
const provisioningEntry = this.provisioningEntryForm.value;
|
||||||
// TODO: Update once language and date settings are setup
|
// TODO: Update once language and date settings are setup
|
||||||
provisioningEntry.locale = 'en';
|
provisioningEntry.locale = 'en';
|
||||||
provisioningEntry.dateFormat = 'dd MMMM yyyy';
|
provisioningEntry.dateFormat = 'yyyy-MM-dd';
|
||||||
provisioningEntry.date = '06 August 2018';
|
if (provisioningEntry.date instanceof Date) {
|
||||||
|
let day = provisioningEntry.date.getDate();
|
||||||
|
let month = provisioningEntry.date.getMonth() + 1;
|
||||||
|
const year = provisioningEntry.date.getFullYear();
|
||||||
|
if (day < 10) {
|
||||||
|
day = `0${day}`;
|
||||||
|
}
|
||||||
|
if (month < 10) {
|
||||||
|
month = `0${month}`;
|
||||||
|
}
|
||||||
|
provisioningEntry.date = `${year}-${month}-${day}`;
|
||||||
|
}
|
||||||
this.accountingService.createProvisioningEntry(provisioningEntry)
|
this.accountingService.createProvisioningEntry(provisioningEntry)
|
||||||
.subscribe((response: any) => {
|
.subscribe((response: any) => {
|
||||||
console.log(response);
|
this.router.navigate(['../view', response.resourceId], { relativeTo: this.route });
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,14 +1,16 @@
|
|||||||
<div class="container m-b-20" fxLayout="row" fxLayoutAlign="end" fxLayoutGap="20px">
|
<div class="container m-b-20" fxLayout="row" fxLayoutAlign="end" fxLayoutGap="20px">
|
||||||
<button mat-raised-button color="primary" [routerLink]="['/accounting/provisioning-entries/create']">
|
<button mat-raised-button color="primary" [routerLink]="['create']">
|
||||||
<mat-icon>add</mat-icon> Create Provisioning Entry
|
<fa-icon icon="plus"></fa-icon>
|
||||||
|
Create Provisioning Entry
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="container">
|
<div class="container">
|
||||||
|
|
||||||
<div fxLayout="row" fxLayoutGap="20px">
|
<div fxLayout="row">
|
||||||
<mat-form-field fxFlex>
|
<mat-form-field fxFlex>
|
||||||
<input matInput (keyup)="applyFilter($event.target.value)" placeholder="Filter">
|
<mat-label>Filter</mat-label>
|
||||||
|
<input matInput (keyup)="applyFilter($event.target.value)">
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -36,9 +38,8 @@
|
|||||||
<ng-container matColumnDef="viewReport">
|
<ng-container matColumnDef="viewReport">
|
||||||
<th mat-header-cell *matHeaderCellDef> View Report </th>
|
<th mat-header-cell *matHeaderCellDef> View Report </th>
|
||||||
<td mat-cell *matCellDef="let provisioningEntry">
|
<td mat-cell *matCellDef="let provisioningEntry">
|
||||||
<button mat-button (click)="viewReport($event, provisioningEntry.id)" [disabled]="true" color="primary">
|
<button mat-button color="primary" [routerLink]="['view', provisioningEntry.id]">
|
||||||
<!-- Tenant Customizable -->
|
<fa-icon icon="eye"></fa-icon> View
|
||||||
<mat-icon>remove_red_eye</mat-icon> View
|
|
||||||
</button>
|
</button>
|
||||||
</td>
|
</td>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
@@ -47,7 +48,7 @@
|
|||||||
<th mat-header-cell *matHeaderCellDef> Recreate Provisioning </th>
|
<th mat-header-cell *matHeaderCellDef> Recreate Provisioning </th>
|
||||||
<td mat-cell *matCellDef="let provisioningEntry">
|
<td mat-cell *matCellDef="let provisioningEntry">
|
||||||
<button mat-button (click)="recreateProvisioning($event, provisioningEntry.id)" [disabled]="provisioningEntry.journalEntry" color="primary">
|
<button mat-button (click)="recreateProvisioning($event, provisioningEntry.id)" [disabled]="provisioningEntry.journalEntry" color="primary">
|
||||||
<mat-icon>edit</mat-icon> Recreate
|
<fa-icon icon="edit"></fa-icon> Recreate
|
||||||
</button>
|
</button>
|
||||||
</td>
|
</td>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
@@ -56,13 +57,13 @@
|
|||||||
<th mat-header-cell *matHeaderCellDef> View Journal Entry </th>
|
<th mat-header-cell *matHeaderCellDef> View Journal Entry </th>
|
||||||
<td mat-cell *matCellDef="let provisioningEntry">
|
<td mat-cell *matCellDef="let provisioningEntry">
|
||||||
<button mat-button (click)="viewJournalEntry($event, provisioningEntry.id)" [disabled]="!provisioningEntry.journalEntry" color="primary">
|
<button mat-button (click)="viewJournalEntry($event, provisioningEntry.id)" [disabled]="!provisioningEntry.journalEntry" color="primary">
|
||||||
<mat-icon>remove_red_eye</mat-icon> View
|
<fa-icon icon="eye"></fa-icon> View
|
||||||
</button>
|
</button>
|
||||||
</td>
|
</td>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
|
|
||||||
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
|
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
|
||||||
<tr mat-row *matRowDef="let row; columns: displayedColumns;" [routerLink]="['/accounting/provisioning-entries/view', row.id]"></tr>
|
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
|
||||||
|
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,14 @@
|
|||||||
|
/** Angular Imports */
|
||||||
import { Component, OnInit, ViewChild } from '@angular/core';
|
import { Component, OnInit, ViewChild } from '@angular/core';
|
||||||
import { MatSort, MatPaginator, MatTableDataSource } from '@angular/material';
|
import { MatSort, MatPaginator, MatTableDataSource } from '@angular/material';
|
||||||
import { Router } from '@angular/router';
|
import { Router, ActivatedRoute } from '@angular/router';
|
||||||
|
|
||||||
|
/** Custom Services */
|
||||||
import { AccountingService } from '../accounting.service';
|
import { AccountingService } from '../accounting.service';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provisioning entries component.
|
||||||
|
*/
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'mifosx-provisioning-entries',
|
selector: 'mifosx-provisioning-entries',
|
||||||
templateUrl: './provisioning-entries.component.html',
|
templateUrl: './provisioning-entries.component.html',
|
||||||
@@ -11,46 +16,76 @@ import { AccountingService } from '../accounting.service';
|
|||||||
})
|
})
|
||||||
export class ProvisioningEntriesComponent implements OnInit {
|
export class ProvisioningEntriesComponent implements OnInit {
|
||||||
|
|
||||||
|
/** Provisioning entry data. */
|
||||||
|
provisioningEntryData: any;
|
||||||
|
/** Columns to be displayed in provisioning entries table. */
|
||||||
displayedColumns: string[] = ['createdUser', 'createdDate', 'journalEntry', 'viewReport', 'recreateProvisioning', 'viewJournalEntry'];
|
displayedColumns: string[] = ['createdUser', 'createdDate', 'journalEntry', 'viewReport', 'recreateProvisioning', 'viewJournalEntry'];
|
||||||
dataSource: any;
|
/** Data source for provisioning entries table. */
|
||||||
|
dataSource: MatTableDataSource<any>;
|
||||||
|
|
||||||
|
/** Paginator for provisioning entries table. */
|
||||||
@ViewChild(MatPaginator) paginator: MatPaginator;
|
@ViewChild(MatPaginator) paginator: MatPaginator;
|
||||||
|
/** Sorter for provisioning entries table. */
|
||||||
@ViewChild(MatSort) sort: MatSort;
|
@ViewChild(MatSort) sort: MatSort;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the provisioning entries data from `resolve`.
|
||||||
|
* @param {AccountingService} accountingService Accounting Service.
|
||||||
|
* @param {ActivatedRoute} route Activated Route.
|
||||||
|
* @param {Router} router Router for navigation.
|
||||||
|
*/
|
||||||
constructor(private accountingService: AccountingService,
|
constructor(private accountingService: AccountingService,
|
||||||
private router: Router) { }
|
private route: ActivatedRoute,
|
||||||
|
private router: Router) {
|
||||||
ngOnInit() {
|
this.route.data.subscribe((data: { provisioningEntries: any }) => {
|
||||||
this.getProvisioningEntries();
|
this.provisioningEntryData = data.provisioningEntries.pageItems;
|
||||||
}
|
|
||||||
|
|
||||||
getProvisioningEntries() {
|
|
||||||
this.accountingService.getProvisioningEntries().subscribe((provisioningEntryData: any) => {
|
|
||||||
this.dataSource = new MatTableDataSource(provisioningEntryData.pageItems);
|
|
||||||
this.dataSource.paginator = this.paginator;
|
|
||||||
this.dataSource.sort = this.sort;
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the provisioning entries table.
|
||||||
|
*/
|
||||||
|
ngOnInit() {
|
||||||
|
this.setProvisioningEntries();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes the data source, paginator and sorter for provisioning entries table.
|
||||||
|
*/
|
||||||
|
setProvisioningEntries() {
|
||||||
|
this.dataSource = new MatTableDataSource(this.provisioningEntryData);
|
||||||
|
this.dataSource.paginator = this.paginator;
|
||||||
|
this.dataSource.sort = this.sort;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Filters data in provisioning entries table based on passed value.
|
||||||
|
* @param {string} filterValue Value to filter data.
|
||||||
|
*/
|
||||||
applyFilter(filterValue: string) {
|
applyFilter(filterValue: string) {
|
||||||
this.dataSource.filter = filterValue.trim().toLowerCase();
|
this.dataSource.filter = filterValue.trim().toLowerCase();
|
||||||
}
|
}
|
||||||
|
|
||||||
viewReport($event: any, provisioningEntryId: number) {
|
/**
|
||||||
// Tenant Customizable
|
* Recreates provisioning entry.
|
||||||
$event.stopPropagation();
|
* @param {Event} $event Event to stop propagation.
|
||||||
}
|
* @param {string} provisioningEntryId Provisioning entry id.
|
||||||
|
*/
|
||||||
recreateProvisioning($event: any, provisioningEntryId: string) {
|
recreateProvisioning($event: Event, provisioningEntryId: string) {
|
||||||
this.accountingService.recreateProvisioningEntries(provisioningEntryId)
|
this.accountingService.recreateProvisioningEntries(provisioningEntryId)
|
||||||
.subscribe((response: any) => {
|
.subscribe((response: any) => {
|
||||||
this.router.navigate(['/accounting/provisioning-entries/view', response.resourceId]);
|
this.router.navigate(['view', response.resourceId], { relativeTo: this.route });
|
||||||
});
|
});
|
||||||
$event.stopPropagation();
|
$event.stopPropagation();
|
||||||
}
|
}
|
||||||
|
|
||||||
viewJournalEntry($event: any, provisioningEntryId: number) {
|
/**
|
||||||
this.router.navigate(['/accounting/provisioning-entries/journal-entries/view', provisioningEntryId]);
|
* View journal entries for the provisioning entry.
|
||||||
|
* @param {Event} $event Event to stop propagation.
|
||||||
|
* @param {number} provisioningEntryId Provisioning entry id.
|
||||||
|
*/
|
||||||
|
viewJournalEntry($event: Event, provisioningEntryId: number) {
|
||||||
|
this.router.navigate(['journal-entries/view', provisioningEntryId], { relativeTo: this.route });
|
||||||
$event.stopPropagation();
|
$event.stopPropagation();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,30 @@
|
|||||||
|
/** Angular Imports */
|
||||||
|
import { Injectable } from '@angular/core';
|
||||||
|
import { Resolve } from '@angular/router';
|
||||||
|
|
||||||
|
/** rxjs Imports */
|
||||||
|
import { Observable } from 'rxjs';
|
||||||
|
|
||||||
|
/** Custom Services */
|
||||||
|
import { AccountingService } from '../accounting.service';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provisioning entries data resolver.
|
||||||
|
*/
|
||||||
|
@Injectable()
|
||||||
|
export class ProvisioningEntriesResolver implements Resolve<Object> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {AccountingService} accountingService Accounting service.
|
||||||
|
*/
|
||||||
|
constructor(private accountingService: AccountingService) {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the provisioning entries data.
|
||||||
|
* @returns {Observable<any>}
|
||||||
|
*/
|
||||||
|
resolve(): Observable<any> {
|
||||||
|
return this.accountingService.getProvisioningEntries();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+31
@@ -0,0 +1,31 @@
|
|||||||
|
/** Angular Imports */
|
||||||
|
import { Injectable } from '@angular/core';
|
||||||
|
import { Resolve, ActivatedRouteSnapshot } from '@angular/router';
|
||||||
|
|
||||||
|
/** rxjs Imports */
|
||||||
|
import { Observable } from 'rxjs';
|
||||||
|
|
||||||
|
/** Custom Services */
|
||||||
|
import { AccountingService } from '../../accounting.service';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provisioning entry entries data resolver.
|
||||||
|
*/
|
||||||
|
@Injectable()
|
||||||
|
export class ProvisioningEntryEntriesResolver implements Resolve<Object> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {AccountingService} accountingService Accounting service.
|
||||||
|
*/
|
||||||
|
constructor(private accountingService: AccountingService) {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the provisioning entry entries data.
|
||||||
|
* @returns {Observable<any>}
|
||||||
|
*/
|
||||||
|
resolve(route: ActivatedRouteSnapshot): Observable<any> {
|
||||||
|
const provisioningEntryId = route.paramMap.get('id');
|
||||||
|
return this.accountingService.getProvisioningEntryEntries(provisioningEntryId);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+31
@@ -0,0 +1,31 @@
|
|||||||
|
/** Angular Imports */
|
||||||
|
import { Injectable } from '@angular/core';
|
||||||
|
import { Resolve, ActivatedRouteSnapshot } from '@angular/router';
|
||||||
|
|
||||||
|
/** rxjs Imports */
|
||||||
|
import { Observable } from 'rxjs';
|
||||||
|
|
||||||
|
/** Custom Services */
|
||||||
|
import { AccountingService } from '../../accounting.service';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provisioning entry data resolver.
|
||||||
|
*/
|
||||||
|
@Injectable()
|
||||||
|
export class ProvisioningEntryResolver implements Resolve<Object> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {AccountingService} accountingService Accounting service.
|
||||||
|
*/
|
||||||
|
constructor(private accountingService: AccountingService) {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the provisioning entry data.
|
||||||
|
* @returns {Observable<any>}
|
||||||
|
*/
|
||||||
|
resolve(route: ActivatedRouteSnapshot): Observable<any> {
|
||||||
|
const provisioningEntryId = route.paramMap.get('id');
|
||||||
|
return this.accountingService.getProvisioningEntry(provisioningEntryId);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+9
-5
@@ -2,7 +2,8 @@
|
|||||||
|
|
||||||
<div class="m-b-20" fxLayout="row" fxLayoutAlign="end" fxLayoutGap="20px">
|
<div class="m-b-20" fxLayout="row" fxLayoutAlign="end" fxLayoutGap="20px">
|
||||||
<button mat-raised-button color="primary" (click)="createProvisioningJournalEntries()" [disabled]="provisioningEntry.journalEntry">
|
<button mat-raised-button color="primary" (click)="createProvisioningJournalEntries()" [disabled]="provisioningEntry.journalEntry">
|
||||||
<mat-icon>add</mat-icon> Create Journal Entries
|
<fa-icon icon="plus"></fa-icon>
|
||||||
|
Create Journal Entries
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -48,15 +49,18 @@
|
|||||||
<div class="container m-t-20" fxLayout="row wrap" fxLayoutGap="2%" fxLayout.lt-md="column">
|
<div class="container m-t-20" fxLayout="row wrap" fxLayoutGap="2%" fxLayout.lt-md="column">
|
||||||
|
|
||||||
<mat-form-field fxFlex="31%">
|
<mat-form-field fxFlex="31%">
|
||||||
<input matInput placeholder="Office Name" [formControl]="officeName" [matAutocomplete]="officeNameAutocomplete">
|
<mat-label>Office Name</mat-label>
|
||||||
|
<input matInput [formControl]="officeName" [matAutocomplete]="officeNameAutocomplete">
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
|
|
||||||
<mat-form-field fxFlex="31%">
|
<mat-form-field fxFlex="31%">
|
||||||
<input matInput placeholder="Loan Product" [formControl]="loanProduct" [matAutocomplete]="loanProductAutocomplete">
|
<mat-label>Loan Product</mat-label>
|
||||||
|
<input matInput [formControl]="loanProduct" [matAutocomplete]="loanProductAutocomplete">
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
|
|
||||||
<mat-form-field fxFlex="31%">
|
<mat-form-field fxFlex="31%">
|
||||||
<input matInput placeholder="Provisioning Category" [formControl]="provisioningCategory" [matAutocomplete]="provisioningCategoryAutocomplete">
|
<mat-label>Provisioning Category</mat-label>
|
||||||
|
<input matInput [formControl]="provisioningCategory" [matAutocomplete]="provisioningCategoryAutocomplete">
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
@@ -122,7 +126,7 @@
|
|||||||
</ng-container>
|
</ng-container>
|
||||||
|
|
||||||
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
|
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
|
||||||
<tr mat-row *matRowDef="let row; columns: displayedColumns;" [routerLink]="['/accounting/provisioning-entries/view', row.id]"></tr>
|
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
|
||||||
|
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
|
|||||||
+3
-3
@@ -6,9 +6,9 @@ table {
|
|||||||
div {
|
div {
|
||||||
margin: 1rem 0;
|
margin: 1rem 0;
|
||||||
word-wrap: break-word;
|
word-wrap: break-word;
|
||||||
}
|
|
||||||
|
|
||||||
.header {
|
&.header {
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+156
-81
@@ -1,12 +1,18 @@
|
|||||||
|
/** Angular Imports */
|
||||||
import { Component, OnInit, ViewChild, AfterViewInit } from '@angular/core';
|
import { Component, OnInit, ViewChild, AfterViewInit } from '@angular/core';
|
||||||
import { ActivatedRoute, Router } from '@angular/router';
|
import { ActivatedRoute, Router } from '@angular/router';
|
||||||
import { FormControl } from '@angular/forms';
|
import { FormControl } from '@angular/forms';
|
||||||
import { MatPaginator, MatSort, MatTableDataSource } from '@angular/material';
|
import { MatPaginator, MatSort, MatTableDataSource } from '@angular/material';
|
||||||
|
|
||||||
|
/** rxjs Imports */
|
||||||
import { startWith, map, debounceTime, distinctUntilChanged, tap } from 'rxjs/operators';
|
import { startWith, map, debounceTime, distinctUntilChanged, tap } from 'rxjs/operators';
|
||||||
|
|
||||||
|
/** Custom Services */
|
||||||
import { AccountingService } from '../../accounting.service';
|
import { AccountingService } from '../../accounting.service';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* View provisioning entry component.
|
||||||
|
*/
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'mifosx-view-provisioning-entry',
|
selector: 'mifosx-view-provisioning-entry',
|
||||||
templateUrl: './view-provisioning-entry.component.html',
|
templateUrl: './view-provisioning-entry.component.html',
|
||||||
@@ -14,41 +20,87 @@ import { AccountingService } from '../../accounting.service';
|
|||||||
})
|
})
|
||||||
export class ViewProvisioningEntryComponent implements OnInit, AfterViewInit {
|
export class ViewProvisioningEntryComponent implements OnInit, AfterViewInit {
|
||||||
|
|
||||||
|
/** Provisioning entry id. */
|
||||||
provisioningEntryId: string;
|
provisioningEntryId: string;
|
||||||
|
/** Provisioning entry. */
|
||||||
provisioningEntry: any;
|
provisioningEntry: any;
|
||||||
|
/** Provisioning entry entries. */
|
||||||
|
provisioningEntryEntries: any;
|
||||||
|
/** Office name filter form control. */
|
||||||
|
officeName = new FormControl();
|
||||||
|
/** Office data. */
|
||||||
|
officeData: any;
|
||||||
|
/** Filtered office data for autocomplete. */
|
||||||
|
filteredOfficeData: any;
|
||||||
|
/** Loan product filter form control. */
|
||||||
|
loanProduct = new FormControl();
|
||||||
|
/** Loan product data. */
|
||||||
|
loanProductData: any;
|
||||||
|
/** Filtered loan product data for autocomplete. */
|
||||||
|
filteredLoanProductData: any;
|
||||||
|
/** Provisioning category filter form control. */
|
||||||
|
provisioningCategory = new FormControl();
|
||||||
|
/** Provisioning category data. */
|
||||||
|
provisioningCategoryData: any;
|
||||||
|
/** Filtered provisioning category data for autocomplete. */
|
||||||
|
filteredProvisioningCategoryData: any;
|
||||||
|
/** Columns to be displayed in provisioning entry entries table. */
|
||||||
displayedColumns: string[] = ['officeName', 'productName', 'currencyCode', 'categoryName', 'amountreserved', 'liabilityAccountName', 'expenseAccountName'];
|
displayedColumns: string[] = ['officeName', 'productName', 'currencyCode', 'categoryName', 'amountreserved', 'liabilityAccountName', 'expenseAccountName'];
|
||||||
dataSource: any;
|
/** Data source for provisioning entry entries table. */
|
||||||
filterValue: any = { officeName: '', productName: '', categoryName: '' };
|
dataSource: MatTableDataSource<any>;
|
||||||
|
/** Provisioning entry entries filter. */
|
||||||
|
filterValue: any = {
|
||||||
|
officeName: '',
|
||||||
|
productName: '',
|
||||||
|
categoryName: ''
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Paginator for provisioning entry entries table. */
|
||||||
@ViewChild(MatPaginator) paginator: MatPaginator;
|
@ViewChild(MatPaginator) paginator: MatPaginator;
|
||||||
|
/** Sorter for provisioning entry entries table. */
|
||||||
@ViewChild(MatSort) sort: MatSort;
|
@ViewChild(MatSort) sort: MatSort;
|
||||||
|
|
||||||
officeName = new FormControl();
|
/**
|
||||||
officeData: any;
|
* Retrieves the provisioning entry, provisioning entry entries, offices,
|
||||||
filteredOfficeData: any;
|
* loan products, provisioning categories data from `resolve`.
|
||||||
|
* @param {AccountingService} accountingService Accounting Service.
|
||||||
loanProduct = new FormControl();
|
* @param {ActivatedRoute} route Activated Route.
|
||||||
loanProductData: any;
|
* @param {Router} router Router for navigation.
|
||||||
filteredLoanProductData: any;
|
*/
|
||||||
|
constructor(private accountingService: AccountingService,
|
||||||
provisioningCategory = new FormControl();
|
private route: ActivatedRoute,
|
||||||
provisioningCategoryData: any;
|
private router: Router) {
|
||||||
filteredProvisioningCategoryData: any;
|
this.route.data.subscribe((data: {
|
||||||
|
provisioningEntry: any,
|
||||||
constructor(private route: ActivatedRoute,
|
provisioningEntryEntries: any,
|
||||||
private router: Router,
|
offices: any,
|
||||||
private accountingService: AccountingService) { }
|
loanProducts: any,
|
||||||
|
provisiningCategories: any
|
||||||
ngOnInit() {
|
}) => {
|
||||||
this.provisioningEntryId = this.route.snapshot.paramMap.get('id');
|
this.provisioningEntryId = data.provisioningEntry.id;
|
||||||
this.getProvisioningEntry();
|
this.provisioningEntry = data.provisioningEntry;
|
||||||
this.getProvisioningEntryEntries();
|
this.provisioningEntryEntries = data.provisioningEntryEntries;
|
||||||
this.getOffices();
|
this.officeData = data.offices;
|
||||||
this.getLoanProducts();
|
this.loanProductData = data.loanProducts;
|
||||||
this.getProvisioningCategories();
|
this.provisioningCategoryData = data.provisiningCategories;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets filtered offices, loan products and provisioning categories for autocomplete
|
||||||
|
* and provisioning entry entries table.
|
||||||
|
*/
|
||||||
|
ngOnInit() {
|
||||||
|
this.setProvisioningEntryEntries();
|
||||||
|
this.setFilteredOffices();
|
||||||
|
this.setFilteredLoanProducts();
|
||||||
|
this.setFilteredProvisioningCategories();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Subscribes to all search filters:
|
||||||
|
* Office Name, Loan Product, Provisioning categories.
|
||||||
|
*/
|
||||||
ngAfterViewInit() {
|
ngAfterViewInit() {
|
||||||
this.officeName.valueChanges
|
this.officeName.valueChanges
|
||||||
.pipe(
|
.pipe(
|
||||||
@@ -84,86 +136,109 @@ export class ViewProvisioningEntryComponent implements OnInit, AfterViewInit {
|
|||||||
.subscribe();
|
.subscribe();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Filter predicate for provisioning entry entries table data.
|
||||||
|
* @param {any} data Table data.
|
||||||
|
* @param {any} filterValue Values to filter data by.
|
||||||
|
*/
|
||||||
filterPredicate(data: any, filterValue: any) {
|
filterPredicate(data: any, filterValue: any) {
|
||||||
return data.officeName.toLowerCase().indexOf(filterValue['officeName']) !== -1
|
return data.officeName.toLowerCase().indexOf(filterValue['officeName']) !== -1
|
||||||
&& data.productName.toLowerCase().indexOf(filterValue['productName']) !== -1
|
&& data.productName.toLowerCase().indexOf(filterValue['productName']) !== -1
|
||||||
&& data.categoryName.toLowerCase().indexOf(filterValue['categoryName']) !== -1;
|
&& data.categoryName.toLowerCase().indexOf(filterValue['categoryName']) !== -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
applyFilter(filterValue: string, property: string) {
|
/**
|
||||||
|
* Initializes the data source, paginator, sorter and filter predicate for
|
||||||
|
* provisioning entry entries table.
|
||||||
|
*/
|
||||||
|
setProvisioningEntryEntries() {
|
||||||
|
this.dataSource = new MatTableDataSource(this.provisioningEntryEntries.pageItems);
|
||||||
|
this.dataSource.paginator = this.paginator;
|
||||||
|
this.dataSource.sort = this.sort;
|
||||||
|
this.dataSource.filterPredicate = this.filterPredicate;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Filters data in provisioning entry entries table based on passed value.
|
||||||
|
* @param {string} filterValue Value to filter data.
|
||||||
|
* @param {string} property Property to filter data.
|
||||||
|
*/
|
||||||
|
applyFilter(filterValue: string, property: string) {
|
||||||
this.filterValue[property] = filterValue;
|
this.filterValue[property] = filterValue;
|
||||||
this.dataSource.filter = this.filterValue;
|
this.dataSource.filter = this.filterValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
getProvisioningEntry() {
|
/**
|
||||||
this.accountingService.getProvisioningEntry(this.provisioningEntryId)
|
* Sets filtered offices for autocomplete.
|
||||||
.subscribe((provisioningEntry: any) => {
|
*/
|
||||||
this.provisioningEntry = provisioningEntry;
|
setFilteredOffices() {
|
||||||
});
|
this.filteredOfficeData = this.officeName.valueChanges
|
||||||
|
.pipe(
|
||||||
|
startWith(''),
|
||||||
|
map((office: any) => typeof office === 'string' ? office : office.name),
|
||||||
|
map((officeName: string) => officeName ? this.filterOfficeAutocompleteData(officeName) : this.officeData)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
getProvisioningEntryEntries() {
|
/**
|
||||||
this.accountingService.getProvisioningEntryEntries(this.provisioningEntryId)
|
* Sets filtered loan products for autocomplete.
|
||||||
.subscribe((provisioningEntryEntries: any) => {
|
*/
|
||||||
this.dataSource = new MatTableDataSource(provisioningEntryEntries.pageItems);
|
setFilteredLoanProducts() {
|
||||||
this.dataSource.paginator = this.paginator;
|
this.filteredLoanProductData = this.loanProduct.valueChanges
|
||||||
this.dataSource.sort = this.sort;
|
.pipe(
|
||||||
this.dataSource.filterPredicate = this.filterPredicate;
|
startWith(''),
|
||||||
});
|
map((loanProduct: any) => typeof loanProduct === 'string' ? loanProduct : loanProduct.name),
|
||||||
|
map((loanProductName: string) => loanProductName ? this.filterLoanProductAutocompleteData(loanProductName) : this.loanProductData)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
getOffices() {
|
/**
|
||||||
this.accountingService.getOffices().subscribe(officeData => {
|
* Sets filtered provisioning categories for autocomplete.
|
||||||
this.officeData = officeData;
|
*/
|
||||||
this.filteredOfficeData = this.officeName.valueChanges
|
setFilteredProvisioningCategories() {
|
||||||
.pipe(
|
this.filteredProvisioningCategoryData = this.provisioningCategory.valueChanges
|
||||||
startWith(''),
|
.pipe(
|
||||||
map((office: any) => typeof office === 'string' ? office : office.name),
|
startWith(''),
|
||||||
map((officeName: string) => officeName ? this.filterOfficeAutocompleteData(this.officeData, officeName) : this.officeData)
|
map((provisioningCategory: any) => typeof provisioningCategory === 'string' ? provisioningCategory : provisioningCategory.categoryName),
|
||||||
);
|
map((provisioningCategoryName: string) => provisioningCategoryName ? this.filterProvisioningCategoryAutocompleteData(provisioningCategoryName) : this.provisioningCategoryData)
|
||||||
});
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
getLoanProducts() {
|
/**
|
||||||
this.accountingService.getLoanProducts().subscribe(loanProductData => {
|
* Filters offices.
|
||||||
this.loanProductData = loanProductData;
|
* @param {string} officeName Office name to filter office by.
|
||||||
this.filteredLoanProductData = this.loanProduct.valueChanges
|
* @returns {any} Filtered offices.
|
||||||
.pipe(
|
*/
|
||||||
startWith(''),
|
private filterOfficeAutocompleteData(officeName: string): any {
|
||||||
map((loanProduct: any) => typeof loanProduct === 'string' ? loanProduct : loanProduct.name),
|
return this.officeData.filter((office: any) => office.name.toLowerCase().includes(officeName.toLowerCase()));
|
||||||
map((loanProductName: string) => loanProductName ? this.filterLoanProductAutocompleteData(this.loanProductData, loanProductName) : this.loanProductData)
|
|
||||||
);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
getProvisioningCategories() {
|
/**
|
||||||
this.accountingService.getProvisioningCategories().subscribe(provisioningCategoryData => {
|
* Filters loan products.
|
||||||
this.provisioningCategoryData = provisioningCategoryData;
|
* @param {string} loanProductName Loan product name to filter loan products by.
|
||||||
this.filteredProvisioningCategoryData = this.provisioningCategory.valueChanges
|
* @returns {any} Filtered loan products.
|
||||||
.pipe(
|
*/
|
||||||
startWith(''),
|
private filterLoanProductAutocompleteData(loanProductName: string): any {
|
||||||
map((provisioningCategory: any) => typeof provisioningCategory === 'string' ? provisioningCategory : provisioningCategory.categoryName),
|
return this.loanProductData.filter((loanProduct: any) => loanProduct.name.toLowerCase().includes(loanProductName.toLocaleLowerCase()));
|
||||||
map((provisioningCategoryName: string) => provisioningCategoryName ? this.filterProvisioningCategoryAutocompleteData(this.provisioningCategoryData, provisioningCategoryName) : this.provisioningCategoryData)
|
|
||||||
);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private filterOfficeAutocompleteData(officeData: any, officeName: string): any {
|
/**
|
||||||
return officeData.filter((office: any) => office.name.toLowerCase().includes(officeName.toLowerCase()));
|
* Filters provisioning categories.
|
||||||
}
|
* @param {string} provisioningCategoryName Provisioning category name to filter provisioning categories by.
|
||||||
|
* @returns {any} Filtered provisioning categories.
|
||||||
private filterLoanProductAutocompleteData(loanProductData: any, loanProductName: string): any {
|
*/
|
||||||
return loanProductData.filter((loanProduct: any) => loanProduct.name.toLowerCase().includes(loanProductName.toLocaleLowerCase()));
|
private filterProvisioningCategoryAutocompleteData(provisioningCategoryName: string): any {
|
||||||
}
|
return this.provisioningCategoryData.filter((provisioningCategory: any) => provisioningCategory.categoryName.toLowerCase().includes(provisioningCategoryName.toLocaleLowerCase()));
|
||||||
|
|
||||||
private filterProvisioningCategoryAutocompleteData(provisioningCategoryData: any, provisioningCategoryName: string): any {
|
|
||||||
return provisioningCategoryData.filter((provisioningCategory: any) => provisioningCategory.categoryName.toLowerCase().includes(provisioningCategoryName.toLocaleLowerCase()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates provisioning journal entries
|
||||||
|
* and redirects to created entries.
|
||||||
|
*/
|
||||||
createProvisioningJournalEntries() {
|
createProvisioningJournalEntries() {
|
||||||
this.accountingService.createProvisioningJournalEntries(this.provisioningEntryId)
|
this.accountingService.createProvisioningJournalEntries(this.provisioningEntryId)
|
||||||
.subscribe((response: any) => {
|
.subscribe((response: any) => {
|
||||||
this.router.navigate(['/accounting/provisioning-entries/journal-entries/view', response.resourceId]);
|
this.router.navigate(['../../journal-entries/view', response.resourceId], { relativeTo: this.route });
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+31
@@ -0,0 +1,31 @@
|
|||||||
|
/** Angular Imports */
|
||||||
|
import { Injectable } from '@angular/core';
|
||||||
|
import { Resolve, ActivatedRouteSnapshot } from '@angular/router';
|
||||||
|
|
||||||
|
/** rxjs Imports */
|
||||||
|
import { Observable } from 'rxjs';
|
||||||
|
|
||||||
|
/** Custom Services */
|
||||||
|
import { AccountingService } from '../../accounting.service';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provisioning journal entries data resolver.
|
||||||
|
*/
|
||||||
|
@Injectable()
|
||||||
|
export class ProvisioningJournalEntriesResolver implements Resolve<Object> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {AccountingService} accountingService Accounting service.
|
||||||
|
*/
|
||||||
|
constructor(private accountingService: AccountingService) {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the provisioning journal entries data.
|
||||||
|
* @returns {Observable<any>}
|
||||||
|
*/
|
||||||
|
resolve(route: ActivatedRouteSnapshot): Observable<any> {
|
||||||
|
const id = route.paramMap.get('id');
|
||||||
|
return this.accountingService.getProvisioningJournalEntries(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+2
-1
@@ -2,7 +2,8 @@
|
|||||||
|
|
||||||
<div fxLayout="row" fxLayoutGap="20px">
|
<div fxLayout="row" fxLayoutGap="20px">
|
||||||
<mat-form-field fxFlex>
|
<mat-form-field fxFlex>
|
||||||
<input matInput (keyup)="applyFilter($event.target.value)" placeholder="Filter">
|
<mat-label>Filter</mat-label>
|
||||||
|
<input matInput (keyup)="applyFilter($event.target.value)">
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
+43
-24
@@ -1,9 +1,11 @@
|
|||||||
|
/** Angular Imports */
|
||||||
import { Component, OnInit, ViewChild } from '@angular/core';
|
import { Component, OnInit, ViewChild } from '@angular/core';
|
||||||
import { ActivatedRoute } from '@angular/router';
|
import { ActivatedRoute } from '@angular/router';
|
||||||
import { MatPaginator, MatSort, MatTableDataSource } from '@angular/material';
|
import { MatPaginator, MatSort, MatTableDataSource } from '@angular/material';
|
||||||
|
|
||||||
import { AccountingService } from '../../accounting.service';
|
/**
|
||||||
|
* View provisioning journal entries component.
|
||||||
|
*/
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'mifosx-view-provisioning-journal-entries',
|
selector: 'mifosx-view-provisioning-journal-entries',
|
||||||
templateUrl: './view-provisioning-journal-entries.component.html',
|
templateUrl: './view-provisioning-journal-entries.component.html',
|
||||||
@@ -11,39 +13,56 @@ import { AccountingService } from '../../accounting.service';
|
|||||||
})
|
})
|
||||||
export class ViewProvisioningJournalEntriesComponent implements OnInit {
|
export class ViewProvisioningJournalEntriesComponent implements OnInit {
|
||||||
|
|
||||||
provisioningEntryId: string;
|
/** Provisioning journal entry data. */
|
||||||
|
provisioningJournalEntryData: any;
|
||||||
|
/** Columns to be displayed in provisioning journal entries table. */
|
||||||
displayedColumns: string[] = ['id', 'officeName', 'transactionDate', 'transactionId', 'glAccountType', 'createdByUserName', 'glAccountCode', 'glAccountName', 'debit', 'credit'];
|
displayedColumns: string[] = ['id', 'officeName', 'transactionDate', 'transactionId', 'glAccountType', 'createdByUserName', 'glAccountCode', 'glAccountName', 'debit', 'credit'];
|
||||||
dataSource: any;
|
/** Data source for provisioning journal entries table. */
|
||||||
|
dataSource: MatTableDataSource<any>;
|
||||||
|
|
||||||
|
/** Paginator for provisioning journal entries table. */
|
||||||
@ViewChild(MatPaginator) paginator: MatPaginator;
|
@ViewChild(MatPaginator) paginator: MatPaginator;
|
||||||
|
/** Sorter for provisioning journal entries table. */
|
||||||
@ViewChild(MatSort) sort: MatSort;
|
@ViewChild(MatSort) sort: MatSort;
|
||||||
|
|
||||||
constructor(private route: ActivatedRoute,
|
/**
|
||||||
private accountingService: AccountingService) { }
|
* Retrieves the provisioning journal entries data from `resolve`.
|
||||||
|
* @param {ActivatedRoute} route Activated Route.
|
||||||
|
*/
|
||||||
|
constructor(private route: ActivatedRoute) {
|
||||||
|
this.route.data.subscribe((data: { provisioningJournalEntry: any }) => {
|
||||||
|
this.provisioningJournalEntryData = data.provisioningJournalEntry.pageItems;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the provisioning journal entries table.
|
||||||
|
*/
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
this.provisioningEntryId = this.route.snapshot.paramMap.get('id');
|
this.setProvisioningJournalEntry();
|
||||||
this.getProvisioningJournalEntry();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
getProvisioningJournalEntry() {
|
/**
|
||||||
this.accountingService.getProvisioningJournalEntries(this.provisioningEntryId)
|
* Initializes the data source, paginator and sorter for provisioning journal entries table.
|
||||||
.subscribe((provisioningJournalEntryData: any) => {
|
*/
|
||||||
this.dataSource = new MatTableDataSource(provisioningJournalEntryData.pageItems);
|
setProvisioningJournalEntry() {
|
||||||
this.dataSource.paginator = this.paginator;
|
this.dataSource = new MatTableDataSource(this.provisioningJournalEntryData);
|
||||||
this.dataSource.sortingDataAccessor = (transaction: any, property: any) => {
|
this.dataSource.paginator = this.paginator;
|
||||||
switch (property) {
|
this.dataSource.sortingDataAccessor = (transaction: any, property: any) => {
|
||||||
case 'glAccountType': return transaction.glAccountType.value;
|
switch (property) {
|
||||||
case 'debit': return transaction.amount;
|
case 'glAccountType': return transaction.glAccountType.value;
|
||||||
case 'credit': return transaction.amount;
|
case 'debit': return transaction.amount;
|
||||||
default: return transaction[property];
|
case 'credit': return transaction.amount;
|
||||||
}
|
default: return transaction[property];
|
||||||
};
|
}
|
||||||
this.dataSource.sort = this.sort;
|
};
|
||||||
});
|
this.dataSource.sort = this.sort;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Filters data in provisioning journal entries table based on passed value.
|
||||||
|
* @param {string} filterValue Value to filter data.
|
||||||
|
*/
|
||||||
applyFilter(filterValue: string) {
|
applyFilter(filterValue: string) {
|
||||||
this.dataSource.filter = filterValue.trim().toLowerCase();
|
this.dataSource.filter = filterValue.trim().toLowerCase();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,8 @@
|
|||||||
<div mat-dialog-content>
|
<div mat-dialog-content>
|
||||||
<p>Are you sure you want to revert this transaction?</p>
|
<p>Are you sure you want to revert this transaction?</p>
|
||||||
<mat-form-field fxFlexFill>
|
<mat-form-field fxFlexFill>
|
||||||
<textarea matInput placeholder="Comments" [formControl]="comments"></textarea>
|
<mat-label>Comments</mat-label>
|
||||||
|
<textarea matInput [formControl]="comments"></textarea>
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
</div>
|
</div>
|
||||||
<mat-dialog-actions align="end">
|
<mat-dialog-actions align="end">
|
||||||
|
|||||||
@@ -1,7 +1,11 @@
|
|||||||
|
/** Angular Imports */
|
||||||
import { Component, OnInit, Inject } from '@angular/core';
|
import { Component, OnInit, Inject } from '@angular/core';
|
||||||
import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material';
|
import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material';
|
||||||
import { FormControl } from '@angular/forms';
|
import { FormControl } from '@angular/forms';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Revert transaction dialog component.
|
||||||
|
*/
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'mifosx-revert-transaction',
|
selector: 'mifosx-revert-transaction',
|
||||||
templateUrl: './revert-transaction.component.html',
|
templateUrl: './revert-transaction.component.html',
|
||||||
@@ -9,8 +13,13 @@ import { FormControl } from '@angular/forms';
|
|||||||
})
|
})
|
||||||
export class RevertTransactionComponent implements OnInit {
|
export class RevertTransactionComponent implements OnInit {
|
||||||
|
|
||||||
|
/** Comments input form control. */
|
||||||
comments = new FormControl('');
|
comments = new FormControl('');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {MatDialogRef} dialogRef Component reference to dialog.
|
||||||
|
* @param {any} data Provides comments or reverted transaction ID.
|
||||||
|
*/
|
||||||
constructor(public dialogRef: MatDialogRef<RevertTransactionComponent>,
|
constructor(public dialogRef: MatDialogRef<RevertTransactionComponent>,
|
||||||
@Inject(MAT_DIALOG_DATA) public data: any) { }
|
@Inject(MAT_DIALOG_DATA) public data: any) { }
|
||||||
|
|
||||||
|
|||||||
@@ -1,32 +1,57 @@
|
|||||||
|
/** Angular Imports */
|
||||||
import { CollectionViewer, DataSource } from '@angular/cdk/collections';
|
import { CollectionViewer, DataSource } from '@angular/cdk/collections';
|
||||||
|
|
||||||
|
/** rxjs Imports */
|
||||||
import { Observable, BehaviorSubject } from 'rxjs';
|
import { Observable, BehaviorSubject } from 'rxjs';
|
||||||
|
|
||||||
|
/** Custom Services */
|
||||||
import { AccountingService } from '../accounting.service';
|
import { AccountingService } from '../accounting.service';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Journal entries custom data source to implement server side filtering, pagination and sorting.
|
||||||
|
*/
|
||||||
export class JournalEntriesDataSource implements DataSource<any> {
|
export class JournalEntriesDataSource implements DataSource<any> {
|
||||||
|
|
||||||
|
/** Journal entries behavior subject to represent loaded journal entries page. */
|
||||||
private journalEntriesSubject = new BehaviorSubject<any[]>([]);
|
private journalEntriesSubject = new BehaviorSubject<any[]>([]);
|
||||||
|
/** Records subject to represent total number of filtered journal entry records. */
|
||||||
private recordsSubject = new BehaviorSubject<number>(0);
|
private recordsSubject = new BehaviorSubject<number>(0);
|
||||||
|
/** Records observable which can be subscribed to get the value of total number of filtered journal entry records. */
|
||||||
public records$ = this.recordsSubject.asObservable();
|
public records$ = this.recordsSubject.asObservable();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {AccountingService} accountingService Accounting Service
|
||||||
|
*/
|
||||||
constructor(private accountingService: AccountingService) { }
|
constructor(private accountingService: AccountingService) { }
|
||||||
|
|
||||||
getJournalEntries(filterBy: any, orderBy: string = '', sortOrder: string = '', offset: number = 0, limit: number = 10) {
|
/**
|
||||||
|
* Gets journal entries on the basis of provided parameters and emits the value.
|
||||||
|
* @param {any} filterBy Properties by which entries should be filtered.
|
||||||
|
* @param {string} orderBy Property by which entries should be sorted.
|
||||||
|
* @param {string} sortOrder Sort order: ascending or descending.
|
||||||
|
* @param {number} pageIndex Page number.
|
||||||
|
* @param {number} limit Number of entries within the page.
|
||||||
|
*/
|
||||||
|
getJournalEntries(filterBy: any, orderBy: string = '', sortOrder: string = '', pageIndex: number = 0, limit: number = 10) {
|
||||||
this.journalEntriesSubject.next([]);
|
this.journalEntriesSubject.next([]);
|
||||||
orderBy = (orderBy === 'debit' || orderBy === 'credit') ? 'amount' : orderBy;
|
orderBy = (orderBy === 'debit' || orderBy === 'credit') ? 'amount' : orderBy;
|
||||||
this.accountingService.getJournalEntries(filterBy, orderBy, sortOrder, offset, limit)
|
this.accountingService.getJournalEntries(filterBy, orderBy, sortOrder, pageIndex * limit, limit)
|
||||||
.subscribe((journalEntries: any) => {
|
.subscribe((journalEntries: any) => {
|
||||||
this.recordsSubject.next(journalEntries.totalFilteredRecords);
|
this.recordsSubject.next(journalEntries.totalFilteredRecords);
|
||||||
this.journalEntriesSubject.next(journalEntries.pageItems);
|
this.journalEntriesSubject.next(journalEntries.pageItems);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {CollectionViewer} collectionViewer
|
||||||
|
*/
|
||||||
connect(collectionViewer: CollectionViewer): Observable<any[]> {
|
connect(collectionViewer: CollectionViewer): Observable<any[]> {
|
||||||
return this.journalEntriesSubject.asObservable();
|
return this.journalEntriesSubject.asObservable();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {CollectionViewer} collectionViewer
|
||||||
|
*/
|
||||||
disconnect(collectionViewer: CollectionViewer): void {
|
disconnect(collectionViewer: CollectionViewer): void {
|
||||||
this.journalEntriesSubject.complete();
|
this.journalEntriesSubject.complete();
|
||||||
this.recordsSubject.complete();
|
this.recordsSubject.complete();
|
||||||
|
|||||||
@@ -1,15 +1,18 @@
|
|||||||
<div class="container" fxLayout="row wrap" fxLayoutGap="2%" fxLayout.lt-md="column">
|
<div class="container" fxLayout="row wrap" fxLayoutGap="2%" fxLayout.lt-md="column">
|
||||||
|
|
||||||
<mat-form-field fxFlex="31%">
|
<mat-form-field fxFlex="31%">
|
||||||
<input matInput placeholder="Office Name" [formControl]="officeName" [matAutocomplete]="officeNameAutocomplete">
|
<mat-label>Office Name</mat-label>
|
||||||
|
<input matInput [formControl]="officeName" [matAutocomplete]="officeNameAutocomplete">
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
|
|
||||||
<mat-form-field fxFlex="31%">
|
<mat-form-field fxFlex="31%">
|
||||||
<input matInput placeholder="GL Account Name or Code" [formControl]="glAccount" [matAutocomplete]="glAccountAutocomplete">
|
<mat-label>GL Account Name or Code</mat-label>
|
||||||
|
<input matInput [formControl]="glAccount" [matAutocomplete]="glAccountAutocomplete">
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
|
|
||||||
<mat-form-field fxFlex="31%">
|
<mat-form-field fxFlex="31%">
|
||||||
<mat-select placeholder="Filter" [formControl]="filter" (selectionChange)="applyFilter($event.value, 'manualEntriesOnly')">
|
<mat-label>Filter</mat-label>
|
||||||
|
<mat-select [formControl]="entryTypeFilter" (selectionChange)="applyFilter($event.value, 'manualEntriesOnly')">
|
||||||
<mat-option *ngFor="let filter of entryTypeFilterData" [value]="filter.value">
|
<mat-option *ngFor="let filter of entryTypeFilterData" [value]="filter.value">
|
||||||
{{ filter.option }}
|
{{ filter.option }}
|
||||||
</mat-option>
|
</mat-option>
|
||||||
@@ -17,19 +20,22 @@
|
|||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
|
|
||||||
<mat-form-field fxFlex="31%">
|
<mat-form-field fxFlex="31%">
|
||||||
<input matInput [min]="minDate" [max]="maxDate" [matDatepicker]="transactionDateFromPicker" placeholder="Transaction Date From" [formControl]="transactionDateFrom">
|
<mat-label>Transaction Date From</mat-label>
|
||||||
|
<input matInput [min]="minDate" [max]="maxDate" [matDatepicker]="transactionDateFromPicker" [formControl]="transactionDateFrom">
|
||||||
<mat-datepicker-toggle matSuffix [for]="transactionDateFromPicker"></mat-datepicker-toggle>
|
<mat-datepicker-toggle matSuffix [for]="transactionDateFromPicker"></mat-datepicker-toggle>
|
||||||
<mat-datepicker #transactionDateFromPicker></mat-datepicker>
|
<mat-datepicker #transactionDateFromPicker></mat-datepicker>
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
|
|
||||||
<mat-form-field fxFlex="31%">
|
<mat-form-field fxFlex="31%">
|
||||||
<input matInput [min]="minDate" [max]="maxDate" [matDatepicker]="transactionDateToPicker" placeholder="Transaction Date To" [formControl]="transactionDateTo">
|
<mat-label>Transaction Date To</mat-label>
|
||||||
|
<input matInput [min]="minDate" [max]="maxDate" [matDatepicker]="transactionDateToPicker" [formControl]="transactionDateTo">
|
||||||
<mat-datepicker-toggle matSuffix [for]="transactionDateToPicker"></mat-datepicker-toggle>
|
<mat-datepicker-toggle matSuffix [for]="transactionDateToPicker"></mat-datepicker-toggle>
|
||||||
<mat-datepicker #transactionDateToPicker></mat-datepicker>
|
<mat-datepicker #transactionDateToPicker></mat-datepicker>
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
|
|
||||||
<mat-form-field fxFlex="31%">
|
<mat-form-field fxFlex="31%">
|
||||||
<input matInput placeholder="Transaction ID" [formControl]="transactionId">
|
<mat-label>Transaction ID</mat-label>
|
||||||
|
<input matInput [formControl]="transactionId">
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
@@ -104,7 +110,7 @@
|
|||||||
</ng-container>
|
</ng-container>
|
||||||
|
|
||||||
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
|
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
|
||||||
<tr mat-row *matRowDef="let row; columns: displayedColumns;" (click)="viewTransaction(row)" class="select"></tr>
|
<tr mat-row *matRowDef="let row; columns: displayedColumns;" [routerLink]="['transactions/view', row.transactionId]" class="select-row"></tr>
|
||||||
|
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user